mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2020-11-18 19:53:40 -08:00
Merge pull request #133 from dutchcoders/ISSUES-86-66
QR code, html5 player
This commit is contained in:
commit
3b60ba16cd
@ -58,6 +58,9 @@ import (
|
|||||||
web "github.com/dutchcoders/transfer.sh-web"
|
web "github.com/dutchcoders/transfer.sh-web"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/russross/blackfriday"
|
"github.com/russross/blackfriday"
|
||||||
|
|
||||||
|
qrcode "github.com/skip2/go-qrcode"
|
||||||
|
"encoding/base64"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -147,6 +150,15 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var png []byte
|
||||||
|
png, err = qrcode.Encode(resolveUrl(r, getURL(r).ResolveReference(r.URL), true), qrcode.High, 150)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
qrCode := base64.StdEncoding.EncodeToString(png)
|
||||||
|
|
||||||
data := struct {
|
data := struct {
|
||||||
ContentType string
|
ContentType string
|
||||||
Content html_template.HTML
|
Content html_template.HTML
|
||||||
@ -155,6 +167,7 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
ContentLength uint64
|
ContentLength uint64
|
||||||
GAKey string
|
GAKey string
|
||||||
UserVoiceKey string
|
UserVoiceKey string
|
||||||
|
QRCode string
|
||||||
}{
|
}{
|
||||||
contentType,
|
contentType,
|
||||||
content,
|
content,
|
||||||
@ -163,6 +176,7 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
contentLength,
|
contentLength,
|
||||||
s.gaKey,
|
s.gaKey,
|
||||||
s.userVoiceKey,
|
s.userVoiceKey,
|
||||||
|
qrCode,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := htmlTemplates.ExecuteTemplate(w, templatePath, data); err != nil {
|
if err := htmlTemplates.ExecuteTemplate(w, templatePath, data); err != nil {
|
||||||
|
2996
vendor/github.com/dutchcoders/transfer.sh-web/bindata_gen.go
generated
vendored
2996
vendor/github.com/dutchcoders/transfer.sh-web/bindata_gen.go
generated
vendored
File diff suppressed because it is too large
Load Diff
4
vendor/github.com/skip2/go-qrcode/.gitignore
generated
vendored
Normal file
4
vendor/github.com/skip2/go-qrcode/.gitignore
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*.sw*
|
||||||
|
*.png
|
||||||
|
*.directory
|
||||||
|
qrcode/qrcode
|
8
vendor/github.com/skip2/go-qrcode/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/skip2/go-qrcode/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.7
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -v ./...
|
||||||
|
|
19
vendor/github.com/skip2/go-qrcode/LICENSE
generated
vendored
Normal file
19
vendor/github.com/skip2/go-qrcode/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2014 Tom Harwood
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
80
vendor/github.com/skip2/go-qrcode/README.md
generated
vendored
Normal file
80
vendor/github.com/skip2/go-qrcode/README.md
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# go-qrcode #
|
||||||
|
|
||||||
|
<img src='https://skip.org/img/nyancat-youtube-qr.png' align='right'>
|
||||||
|
|
||||||
|
Package qrcode implements a QR Code encoder. [](https://travis-ci.org/skip2/go-qrcode)
|
||||||
|
|
||||||
|
A QR Code is a matrix (two-dimensional) barcode. Arbitrary content may be encoded, with URLs being a popular choice :)
|
||||||
|
|
||||||
|
Each QR Code contains error recovery information to aid reading damaged or obscured codes. There are four levels of error recovery: Low, medium, high and highest. QR Codes with a higher recovery level are more robust to damage, at the cost of being physically larger.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
go get -u github.com/skip2/go-qrcode/...
|
||||||
|
|
||||||
|
A command-line tool `qrcode` will be built into `$GOPATH/bin/`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
import qrcode "github.com/skip2/go-qrcode"
|
||||||
|
|
||||||
|
- **Create a PNG image:**
|
||||||
|
|
||||||
|
var png []byte
|
||||||
|
png, err := qrcode.Encode("https://example.org", qrcode.Medium, 256)
|
||||||
|
|
||||||
|
- **Create a PNG image and write to a file:**
|
||||||
|
|
||||||
|
err := qrcode.WriteFile("https://example.org", qrcode.Medium, 256, "qr.png")
|
||||||
|
|
||||||
|
- **Create a PNG image with custom colors and write to file:**
|
||||||
|
|
||||||
|
err := qrcode.WriteColorFile("https://example.org", qrcode.Medium, 256, color.Black, color.White, "qr.png")
|
||||||
|
|
||||||
|
All examples use the qrcode.Medium error Recovery Level and create a fixed
|
||||||
|
256x256px size QR Code. The last function creates a white on black instead of black
|
||||||
|
on white QR Code.
|
||||||
|
|
||||||
|
The maximum capacity of a QR Code varies according to the content encoded and
|
||||||
|
the error recovery level. The maximum capacity is 2,953 bytes, 4,296
|
||||||
|
alphanumeric characters, 7,089 numeric digits, or a combination of these.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
[](https://godoc.org/github.com/skip2/go-qrcode)
|
||||||
|
|
||||||
|
## Demoapp
|
||||||
|
|
||||||
|
[http://go-qrcode.appspot.com](http://go-qrcode.appspot.com)
|
||||||
|
|
||||||
|
## CLI
|
||||||
|
|
||||||
|
A command-line tool `qrcode` will be built into `$GOPATH/bin/`.
|
||||||
|
|
||||||
|
```
|
||||||
|
qrcode -- QR Code encoder in Go
|
||||||
|
https://github.com/skip2/go-qrcode
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
-o string
|
||||||
|
out PNG file prefix, empty for stdout
|
||||||
|
-s int
|
||||||
|
image size (pixel) (default 256)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
1. Arguments except for flags are joined by " " and used to generate QR code.
|
||||||
|
Default output is STDOUT, pipe to imagemagick command "display" to display
|
||||||
|
on any X server.
|
||||||
|
|
||||||
|
qrcode hello word | display
|
||||||
|
|
||||||
|
2. Save to file if "display" not available:
|
||||||
|
|
||||||
|
qrcode "homepage: https://github.com/skip2/go-qrcode" > out.png
|
||||||
|
```
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- [http://en.wikipedia.org/wiki/QR_code](http://en.wikipedia.org/wiki/QR_code)
|
||||||
|
- [ISO/IEC 18004:2006](http://www.iso.org/iso/catalogue_detail.htm?csnumber=43655) - Main QR Code specification (approx CHF 198,00)<br>
|
||||||
|
- [https://github.com/qpliu/qrencode-go/](https://github.com/qpliu/qrencode-go/) - alternative Go QR encoding library based on [ZXing](https://github.com/zxing/zxing)
|
273
vendor/github.com/skip2/go-qrcode/bitset/bitset.go
generated
vendored
Normal file
273
vendor/github.com/skip2/go-qrcode/bitset/bitset.go
generated
vendored
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
// Package bitset implements an append only bit array.
|
||||||
|
//
|
||||||
|
// To create a Bitset and append some bits:
|
||||||
|
// // Bitset Contents
|
||||||
|
// b := bitset.New() // {}
|
||||||
|
// b.AppendBools(true, true, false) // {1, 1, 0}
|
||||||
|
// b.AppendBools(true) // {1, 1, 0, 1}
|
||||||
|
// b.AppendValue(0x02, 4) // {1, 1, 0, 1, 0, 0, 1, 0}
|
||||||
|
//
|
||||||
|
// To read values:
|
||||||
|
//
|
||||||
|
// len := b.Len() // 8
|
||||||
|
// v := b.At(0) // 1
|
||||||
|
// v = b.At(1) // 1
|
||||||
|
// v = b.At(2) // 0
|
||||||
|
// v = b.At(8) // 0
|
||||||
|
package bitset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
b0 = false
|
||||||
|
b1 = true
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bitset stores an array of bits.
|
||||||
|
type Bitset struct {
|
||||||
|
// The number of bits stored.
|
||||||
|
numBits int
|
||||||
|
|
||||||
|
// Storage for individual bits.
|
||||||
|
bits []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns an initialised Bitset with optional initial bits v.
|
||||||
|
func New(v ...bool) *Bitset {
|
||||||
|
b := &Bitset{numBits: 0, bits: make([]byte, 0)}
|
||||||
|
b.AppendBools(v...)
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone returns a copy.
|
||||||
|
func Clone(from *Bitset) *Bitset {
|
||||||
|
return &Bitset{numBits: from.numBits, bits: from.bits[:]}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Substr returns a substring, consisting of the bits from indexes start to end.
|
||||||
|
func (b *Bitset) Substr(start int, end int) *Bitset {
|
||||||
|
if start > end || end > b.numBits {
|
||||||
|
log.Panicf("Out of range start=%d end=%d numBits=%d", start, end, b.numBits)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := New()
|
||||||
|
result.ensureCapacity(end - start)
|
||||||
|
|
||||||
|
for i := start; i < end; i++ {
|
||||||
|
if b.At(i) {
|
||||||
|
result.bits[result.numBits/8] |= 0x80 >> uint(result.numBits%8)
|
||||||
|
}
|
||||||
|
result.numBits++
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFromBase2String constructs and returns a Bitset from a string. The string
|
||||||
|
// consists of '1', '0' or ' ' characters, e.g. "1010 0101". The '1' and '0'
|
||||||
|
// characters represent true/false bits respectively, and ' ' characters are
|
||||||
|
// ignored.
|
||||||
|
//
|
||||||
|
// The function panics if the input string contains other characters.
|
||||||
|
func NewFromBase2String(b2string string) *Bitset {
|
||||||
|
b := &Bitset{numBits: 0, bits: make([]byte, 0)}
|
||||||
|
|
||||||
|
for _, c := range b2string {
|
||||||
|
switch c {
|
||||||
|
case '1':
|
||||||
|
b.AppendBools(true)
|
||||||
|
case '0':
|
||||||
|
b.AppendBools(false)
|
||||||
|
case ' ':
|
||||||
|
default:
|
||||||
|
log.Panicf("Invalid char %c in NewFromBase2String", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendBytes appends a list of whole bytes.
|
||||||
|
func (b *Bitset) AppendBytes(data []byte) {
|
||||||
|
for _, d := range data {
|
||||||
|
b.AppendByte(d, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendByte appends the numBits least significant bits from value.
|
||||||
|
func (b *Bitset) AppendByte(value byte, numBits int) {
|
||||||
|
b.ensureCapacity(numBits)
|
||||||
|
|
||||||
|
if numBits > 8 {
|
||||||
|
log.Panicf("numBits %d out of range 0-8", numBits)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := numBits - 1; i >= 0; i-- {
|
||||||
|
if value&(1<<uint(i)) != 0 {
|
||||||
|
b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.numBits++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendUint32 appends the numBits least significant bits from value.
|
||||||
|
func (b *Bitset) AppendUint32(value uint32, numBits int) {
|
||||||
|
b.ensureCapacity(numBits)
|
||||||
|
|
||||||
|
if numBits > 32 {
|
||||||
|
log.Panicf("numBits %d out of range 0-32", numBits)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := numBits - 1; i >= 0; i-- {
|
||||||
|
if value&(1<<uint(i)) != 0 {
|
||||||
|
b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.numBits++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureCapacity ensures the Bitset can store an additional |numBits|.
|
||||||
|
//
|
||||||
|
// The underlying array is expanded if necessary. To prevent frequent
|
||||||
|
// reallocation, expanding the underlying array at least doubles its capacity.
|
||||||
|
func (b *Bitset) ensureCapacity(numBits int) {
|
||||||
|
numBits += b.numBits
|
||||||
|
|
||||||
|
newNumBytes := numBits / 8
|
||||||
|
if numBits%8 != 0 {
|
||||||
|
newNumBytes++
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(b.bits) >= newNumBytes {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b.bits = append(b.bits, make([]byte, newNumBytes+2*len(b.bits))...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append bits copied from |other|.
|
||||||
|
//
|
||||||
|
// The new length is b.Len() + other.Len().
|
||||||
|
func (b *Bitset) Append(other *Bitset) {
|
||||||
|
b.ensureCapacity(other.numBits)
|
||||||
|
|
||||||
|
for i := 0; i < other.numBits; i++ {
|
||||||
|
if other.At(i) {
|
||||||
|
b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8)
|
||||||
|
}
|
||||||
|
b.numBits++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendBools appends bits to the Bitset.
|
||||||
|
func (b *Bitset) AppendBools(bits ...bool) {
|
||||||
|
b.ensureCapacity(len(bits))
|
||||||
|
|
||||||
|
for _, v := range bits {
|
||||||
|
if v {
|
||||||
|
b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8)
|
||||||
|
}
|
||||||
|
b.numBits++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendNumBools appends num bits of value value.
|
||||||
|
func (b *Bitset) AppendNumBools(num int, value bool) {
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
b.AppendBools(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a human readable representation of the Bitset's contents.
|
||||||
|
func (b *Bitset) String() string {
|
||||||
|
var bitString string
|
||||||
|
for i := 0; i < b.numBits; i++ {
|
||||||
|
if (i % 8) == 0 {
|
||||||
|
bitString += " "
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.bits[i/8] & (0x80 >> byte(i%8))) != 0 {
|
||||||
|
bitString += "1"
|
||||||
|
} else {
|
||||||
|
bitString += "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("numBits=%d, bits=%s", b.numBits, bitString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the length of the Bitset in bits.
|
||||||
|
func (b *Bitset) Len() int {
|
||||||
|
return b.numBits
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bits returns the contents of the Bitset.
|
||||||
|
func (b *Bitset) Bits() []bool {
|
||||||
|
result := make([]bool, b.numBits)
|
||||||
|
|
||||||
|
var i int
|
||||||
|
for i = 0; i < b.numBits; i++ {
|
||||||
|
result[i] = (b.bits[i/8] & (0x80 >> byte(i%8))) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// At returns the value of the bit at |index|.
|
||||||
|
func (b *Bitset) At(index int) bool {
|
||||||
|
if index >= b.numBits {
|
||||||
|
log.Panicf("Index %d out of range", index)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (b.bits[index/8] & (0x80 >> byte(index%8))) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equals returns true if the Bitset equals other.
|
||||||
|
func (b *Bitset) Equals(other *Bitset) bool {
|
||||||
|
if b.numBits != other.numBits {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(b.bits[0:b.numBits/8], other.bits[0:b.numBits/8]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 8 * (b.numBits / 8); i < b.numBits; i++ {
|
||||||
|
a := (b.bits[i/8] & (0x80 >> byte(i%8)))
|
||||||
|
b := (other.bits[i/8] & (0x80 >> byte(i%8)))
|
||||||
|
|
||||||
|
if a != b {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByteAt returns a byte consisting of upto 8 bits starting at index.
|
||||||
|
func (b *Bitset) ByteAt(index int) byte {
|
||||||
|
if index < 0 || index >= b.numBits {
|
||||||
|
log.Panicf("Index %d out of range", index)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result byte
|
||||||
|
|
||||||
|
for i := index; i < index+8 && i < b.numBits; i++ {
|
||||||
|
result <<= 1
|
||||||
|
if b.At(i) {
|
||||||
|
result |= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
321
vendor/github.com/skip2/go-qrcode/bitset/bitset_test.go
generated
vendored
Normal file
321
vendor/github.com/skip2/go-qrcode/bitset/bitset_test.go
generated
vendored
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package bitset
|
||||||
|
|
||||||
|
import (
|
||||||
|
rand "math/rand"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewBitset(t *testing.T) {
|
||||||
|
tests := [][]bool{
|
||||||
|
{},
|
||||||
|
{b1},
|
||||||
|
{b0},
|
||||||
|
{b1, b0},
|
||||||
|
{b1, b0, b1},
|
||||||
|
{b0, b0, b1},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range tests {
|
||||||
|
result := New(v...)
|
||||||
|
|
||||||
|
if !equal(result.Bits(), v) {
|
||||||
|
t.Errorf("%s", result.String())
|
||||||
|
t.Errorf("%v => %v, want %v", v, result.Bits(), v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppend(t *testing.T) {
|
||||||
|
randomBools := make([]bool, 128)
|
||||||
|
|
||||||
|
rng := rand.New(rand.NewSource(1))
|
||||||
|
|
||||||
|
for i := 0; i < len(randomBools); i++ {
|
||||||
|
randomBools[i] = rng.Intn(2) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(randomBools)-1; i++ {
|
||||||
|
a := New(randomBools[0:i]...)
|
||||||
|
b := New(randomBools[i:]...)
|
||||||
|
|
||||||
|
a.Append(b)
|
||||||
|
|
||||||
|
if !equal(a.Bits(), randomBools) {
|
||||||
|
t.Errorf("got %v, want %v", a.Bits(), randomBools)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppendByte(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
initial *Bitset
|
||||||
|
value byte
|
||||||
|
numBits int
|
||||||
|
expected *Bitset
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
New(),
|
||||||
|
0x01,
|
||||||
|
1,
|
||||||
|
New(b1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
New(b1),
|
||||||
|
0x01,
|
||||||
|
1,
|
||||||
|
New(b1, b1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
New(b0),
|
||||||
|
0x01,
|
||||||
|
1,
|
||||||
|
New(b0, b1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
New(b1, b0, b1, b0, b1, b0, b1),
|
||||||
|
0xAA, // 0b10101010
|
||||||
|
2,
|
||||||
|
New(b1, b0, b1, b0, b1, b0, b1, b1, b0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
New(b1, b0, b1, b0, b1, b0, b1),
|
||||||
|
0xAA, // 0b10101010
|
||||||
|
8,
|
||||||
|
New(b1, b0, b1, b0, b1, b0, b1, b1, b0, b1, b0, b1, b0, b1, b0),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test.initial.AppendByte(test.value, test.numBits)
|
||||||
|
if !equal(test.initial.Bits(), test.expected.Bits()) {
|
||||||
|
t.Errorf("Got %v, expected %v", test.initial.Bits(),
|
||||||
|
test.expected.Bits())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppendUint32(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
initial *Bitset
|
||||||
|
value uint32
|
||||||
|
numBits int
|
||||||
|
expected *Bitset
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
New(),
|
||||||
|
0xAAAAAAAF,
|
||||||
|
4,
|
||||||
|
New(b1, b1, b1, b1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
New(),
|
||||||
|
0xFFFFFFFF,
|
||||||
|
32,
|
||||||
|
New(b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1,
|
||||||
|
b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
New(),
|
||||||
|
0x0,
|
||||||
|
32,
|
||||||
|
New(b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0,
|
||||||
|
b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
New(),
|
||||||
|
0xAAAAAAAA,
|
||||||
|
32,
|
||||||
|
New(b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1,
|
||||||
|
b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
New(),
|
||||||
|
0xAAAAAAAA,
|
||||||
|
31,
|
||||||
|
New(b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1,
|
||||||
|
b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test.initial.AppendUint32(test.value, test.numBits)
|
||||||
|
if !equal(test.initial.Bits(), test.expected.Bits()) {
|
||||||
|
t.Errorf("Got %v, expected %v", test.initial.Bits(),
|
||||||
|
test.expected.Bits())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppendBools(t *testing.T) {
|
||||||
|
randomBools := make([]bool, 128)
|
||||||
|
|
||||||
|
rng := rand.New(rand.NewSource(1))
|
||||||
|
|
||||||
|
for i := 0; i < len(randomBools); i++ {
|
||||||
|
randomBools[i] = rng.Intn(2) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(randomBools)-1; i++ {
|
||||||
|
result := New(randomBools[0:i]...)
|
||||||
|
result.AppendBools(randomBools[i:]...)
|
||||||
|
|
||||||
|
if !equal(result.Bits(), randomBools) {
|
||||||
|
t.Errorf("got %v, want %v", result.Bits(), randomBools)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkShortAppend(b *testing.B) {
|
||||||
|
bitset := New()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bitset.AppendBools(b0, b1, b0, b1, b0, b1, b0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLen(t *testing.T) {
|
||||||
|
randomBools := make([]bool, 128)
|
||||||
|
|
||||||
|
rng := rand.New(rand.NewSource(1))
|
||||||
|
|
||||||
|
for i := 0; i < len(randomBools); i++ {
|
||||||
|
randomBools[i] = rng.Intn(2) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(randomBools)-1; i++ {
|
||||||
|
result := New(randomBools[0:i]...)
|
||||||
|
|
||||||
|
if result.Len() != i {
|
||||||
|
t.Errorf("Len = %d, want %d", result.Len(), i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAt(t *testing.T) {
|
||||||
|
test := []bool{b0, b1, b0, b1, b0, b1, b1, b0, b1}
|
||||||
|
|
||||||
|
bitset := New(test...)
|
||||||
|
for i, v := range test {
|
||||||
|
result := bitset.At(i)
|
||||||
|
|
||||||
|
if result != test[i] {
|
||||||
|
t.Errorf("bitset[%d] => %t, want %t", i, result, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func equal(a []bool, b []bool) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(a); i++ {
|
||||||
|
if a[i] != b[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExample(t *testing.T) {
|
||||||
|
b := New() // {}
|
||||||
|
b.AppendBools(true, true, false) // {1, 1, 0}
|
||||||
|
b.AppendBools(true) // {1, 1, 0, 1}
|
||||||
|
b.AppendByte(0x02, 4) // {1, 1, 0, 1, 0, 0, 1, 0}
|
||||||
|
|
||||||
|
expected := []bool{b1, b1, b0, b1, b0, b0, b1, b0}
|
||||||
|
|
||||||
|
if !equal(b.Bits(), expected) {
|
||||||
|
t.Errorf("Got %v, expected %v", b.Bits(), expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestByteAt(t *testing.T) {
|
||||||
|
data := []bool{b0, b1, b0, b1, b0, b1, b1, b0, b1}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
index int
|
||||||
|
expected byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
0x56,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
1,
|
||||||
|
0xad,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
2,
|
||||||
|
0x2d,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
5,
|
||||||
|
0x0d,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
8,
|
||||||
|
0x01,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
b := New()
|
||||||
|
b.AppendBools(data...)
|
||||||
|
|
||||||
|
result := b.ByteAt(test.index)
|
||||||
|
|
||||||
|
if result != test.expected {
|
||||||
|
t.Errorf("Got %#x, expected %#x", result, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubstr(t *testing.T) {
|
||||||
|
data := []bool{b0, b1, b0, b1, b0, b1, b1, b0}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
start int
|
||||||
|
end int
|
||||||
|
expected []bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
[]bool{b0, b1, b0, b1, b0, b1, b1, b0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
[]bool{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
[]bool{b0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
[]bool{b0, b1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
b := New()
|
||||||
|
b.AppendBools(data...)
|
||||||
|
|
||||||
|
result := b.Substr(test.start, test.end)
|
||||||
|
|
||||||
|
expected := New()
|
||||||
|
expected.AppendBools(test.expected...)
|
||||||
|
|
||||||
|
if !result.Equals(expected) {
|
||||||
|
t.Errorf("Got %s, expected %s", result.String(), expected.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
455
vendor/github.com/skip2/go-qrcode/encoder.go
generated
vendored
Normal file
455
vendor/github.com/skip2/go-qrcode/encoder.go
generated
vendored
Normal file
@ -0,0 +1,455 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Data encoding.
|
||||||
|
//
|
||||||
|
// The main data portion of a QR Code consists of one or more segments of data.
|
||||||
|
// A segment consists of:
|
||||||
|
//
|
||||||
|
// - The segment Data Mode: numeric, alphanumeric, or byte.
|
||||||
|
// - The length of segment in bits.
|
||||||
|
// - Encoded data.
|
||||||
|
//
|
||||||
|
// For example, the string "123ZZ#!#!" may be represented as:
|
||||||
|
//
|
||||||
|
// [numeric, 3, "123"] [alphanumeric, 2, "ZZ"] [byte, 4, "#!#!"]
|
||||||
|
//
|
||||||
|
// Multiple data modes exist to minimise the size of encoded data. For example,
|
||||||
|
// 8-bit bytes require 8 bits to encode each, but base 10 numeric data can be
|
||||||
|
// encoded at a higher density of 3 numbers (e.g. 123) per 10 bits.
|
||||||
|
//
|
||||||
|
// Some data can be represented in multiple modes. Numeric data can be
|
||||||
|
// represented in all three modes, whereas alphanumeric data (e.g. 'A') can be
|
||||||
|
// represented in alphanumeric and byte mode.
|
||||||
|
//
|
||||||
|
// Starting a new segment (to use a different Data Mode) has a cost, the bits to
|
||||||
|
// state the new segment Data Mode and length. To minimise each QR Code's symbol
|
||||||
|
// size, an optimisation routine coalesces segment types where possible, to
|
||||||
|
// reduce the encoded data length.
|
||||||
|
//
|
||||||
|
// There are several other data modes available (e.g. Kanji mode) which are not
|
||||||
|
// implemented here.
|
||||||
|
|
||||||
|
// A segment encoding mode.
|
||||||
|
type dataMode uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Each dataMode is a subset of the subsequent dataMode:
|
||||||
|
// dataModeNone < dataModeNumeric < dataModeAlphanumeric < dataModeByte
|
||||||
|
//
|
||||||
|
// This ordering is important for determining which data modes a character can
|
||||||
|
// be encoded with. E.g. 'E' can be encoded in both dataModeAlphanumeric and
|
||||||
|
// dataModeByte.
|
||||||
|
dataModeNone dataMode = 1 << iota
|
||||||
|
dataModeNumeric
|
||||||
|
dataModeAlphanumeric
|
||||||
|
dataModeByte
|
||||||
|
)
|
||||||
|
|
||||||
|
// dataModeString returns d as a short printable string.
|
||||||
|
func dataModeString(d dataMode) string {
|
||||||
|
switch d {
|
||||||
|
case dataModeNone:
|
||||||
|
return "none"
|
||||||
|
case dataModeNumeric:
|
||||||
|
return "numeric"
|
||||||
|
case dataModeAlphanumeric:
|
||||||
|
return "alphanumeric"
|
||||||
|
case dataModeByte:
|
||||||
|
return "byte"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
type dataEncoderType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
dataEncoderType1To9 dataEncoderType = iota
|
||||||
|
dataEncoderType10To26
|
||||||
|
dataEncoderType27To40
|
||||||
|
)
|
||||||
|
|
||||||
|
// segment is a single segment of data.
|
||||||
|
type segment struct {
|
||||||
|
// Data Mode (e.g. numeric).
|
||||||
|
dataMode dataMode
|
||||||
|
|
||||||
|
// segment data (e.g. "abc").
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// A dataEncoder encodes data for a particular QR Code version.
|
||||||
|
type dataEncoder struct {
|
||||||
|
// Minimum & maximum versions supported.
|
||||||
|
minVersion int
|
||||||
|
maxVersion int
|
||||||
|
|
||||||
|
// Mode indicator bit sequences.
|
||||||
|
numericModeIndicator *bitset.Bitset
|
||||||
|
alphanumericModeIndicator *bitset.Bitset
|
||||||
|
byteModeIndicator *bitset.Bitset
|
||||||
|
|
||||||
|
// Character count lengths.
|
||||||
|
numNumericCharCountBits int
|
||||||
|
numAlphanumericCharCountBits int
|
||||||
|
numByteCharCountBits int
|
||||||
|
|
||||||
|
// The raw input data.
|
||||||
|
data []byte
|
||||||
|
|
||||||
|
// The data classified into unoptimised segments.
|
||||||
|
actual []segment
|
||||||
|
|
||||||
|
// The data classified into optimised segments.
|
||||||
|
optimised []segment
|
||||||
|
}
|
||||||
|
|
||||||
|
// newDataEncoder constructs a dataEncoder.
|
||||||
|
func newDataEncoder(t dataEncoderType) *dataEncoder {
|
||||||
|
d := &dataEncoder{}
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case dataEncoderType1To9:
|
||||||
|
d = &dataEncoder{
|
||||||
|
minVersion: 1,
|
||||||
|
maxVersion: 9,
|
||||||
|
numericModeIndicator: bitset.New(b0, b0, b0, b1),
|
||||||
|
alphanumericModeIndicator: bitset.New(b0, b0, b1, b0),
|
||||||
|
byteModeIndicator: bitset.New(b0, b1, b0, b0),
|
||||||
|
numNumericCharCountBits: 10,
|
||||||
|
numAlphanumericCharCountBits: 9,
|
||||||
|
numByteCharCountBits: 8,
|
||||||
|
}
|
||||||
|
case dataEncoderType10To26:
|
||||||
|
d = &dataEncoder{
|
||||||
|
minVersion: 10,
|
||||||
|
maxVersion: 26,
|
||||||
|
numericModeIndicator: bitset.New(b0, b0, b0, b1),
|
||||||
|
alphanumericModeIndicator: bitset.New(b0, b0, b1, b0),
|
||||||
|
byteModeIndicator: bitset.New(b0, b1, b0, b0),
|
||||||
|
numNumericCharCountBits: 12,
|
||||||
|
numAlphanumericCharCountBits: 11,
|
||||||
|
numByteCharCountBits: 16,
|
||||||
|
}
|
||||||
|
case dataEncoderType27To40:
|
||||||
|
d = &dataEncoder{
|
||||||
|
minVersion: 27,
|
||||||
|
maxVersion: 40,
|
||||||
|
numericModeIndicator: bitset.New(b0, b0, b0, b1),
|
||||||
|
alphanumericModeIndicator: bitset.New(b0, b0, b1, b0),
|
||||||
|
byteModeIndicator: bitset.New(b0, b1, b0, b0),
|
||||||
|
numNumericCharCountBits: 14,
|
||||||
|
numAlphanumericCharCountBits: 13,
|
||||||
|
numByteCharCountBits: 16,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Panic("Unknown dataEncoderType")
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode data as one or more segments and return the encoded data.
|
||||||
|
//
|
||||||
|
// The returned data does not include the terminator bit sequence.
|
||||||
|
func (d *dataEncoder) encode(data []byte) (*bitset.Bitset, error) {
|
||||||
|
d.data = data
|
||||||
|
d.actual = nil
|
||||||
|
d.optimised = nil
|
||||||
|
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil, errors.New("no data to encode")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Classify data into unoptimised segments.
|
||||||
|
d.classifyDataModes()
|
||||||
|
|
||||||
|
// Optimise segments.
|
||||||
|
err := d.optimiseDataModes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode data.
|
||||||
|
encoded := bitset.New()
|
||||||
|
for _, s := range d.optimised {
|
||||||
|
d.encodeDataRaw(s.data, s.dataMode, encoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// classifyDataModes classifies the raw data into unoptimised segments.
|
||||||
|
// e.g. "123ZZ#!#!" =>
|
||||||
|
// [numeric, 3, "123"] [alphanumeric, 2, "ZZ"] [byte, 4, "#!#!"].
|
||||||
|
func (d *dataEncoder) classifyDataModes() {
|
||||||
|
var start int
|
||||||
|
mode := dataModeNone
|
||||||
|
|
||||||
|
for i, v := range d.data {
|
||||||
|
newMode := dataModeNone
|
||||||
|
switch {
|
||||||
|
case v >= 0x30 && v <= 0x39:
|
||||||
|
newMode = dataModeNumeric
|
||||||
|
case v == 0x20 || v == 0x24 || v == 0x25 || v == 0x2a || v == 0x2b || v ==
|
||||||
|
0x2d || v == 0x2e || v == 0x2f || v == 0x3a || (v >= 0x41 && v <= 0x5a):
|
||||||
|
newMode = dataModeAlphanumeric
|
||||||
|
default:
|
||||||
|
newMode = dataModeByte
|
||||||
|
}
|
||||||
|
|
||||||
|
if newMode != mode {
|
||||||
|
if i > 0 {
|
||||||
|
d.actual = append(d.actual, segment{dataMode: mode, data: d.data[start:i]})
|
||||||
|
|
||||||
|
start = i
|
||||||
|
}
|
||||||
|
|
||||||
|
mode = newMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.actual = append(d.actual, segment{dataMode: mode, data: d.data[start:len(d.data)]})
|
||||||
|
}
|
||||||
|
|
||||||
|
// optimiseDataModes optimises the list of segments to reduce the overall output
|
||||||
|
// encoded data length.
|
||||||
|
//
|
||||||
|
// The algorithm coalesces adjacent segments. segments are only coalesced when
|
||||||
|
// the Data Modes are compatible, and when the coalesced segment has a shorter
|
||||||
|
// encoded length than separate segments.
|
||||||
|
//
|
||||||
|
// Multiple segments may be coalesced. For example a string of alternating
|
||||||
|
// alphanumeric/numeric segments ANANANANA can be optimised to just A.
|
||||||
|
func (d *dataEncoder) optimiseDataModes() error {
|
||||||
|
for i := 0; i < len(d.actual); {
|
||||||
|
mode := d.actual[i].dataMode
|
||||||
|
numChars := len(d.actual[i].data)
|
||||||
|
|
||||||
|
j := i + 1
|
||||||
|
for j < len(d.actual) {
|
||||||
|
nextNumChars := len(d.actual[j].data)
|
||||||
|
nextMode := d.actual[j].dataMode
|
||||||
|
|
||||||
|
if nextMode > mode {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
coalescedLength, err := d.encodedLength(mode, numChars+nextNumChars)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
seperateLength1, err := d.encodedLength(mode, numChars)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
seperateLength2, err := d.encodedLength(nextMode, nextNumChars)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if coalescedLength < seperateLength1+seperateLength2 {
|
||||||
|
j++
|
||||||
|
numChars += nextNumChars
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
optimised := segment{dataMode: mode,
|
||||||
|
data: make([]byte, 0, numChars)}
|
||||||
|
|
||||||
|
for k := i; k < j; k++ {
|
||||||
|
optimised.data = append(optimised.data, d.actual[k].data...)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.optimised = append(d.optimised, optimised)
|
||||||
|
|
||||||
|
i = j
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeDataRaw encodes data in dataMode. The encoded data is appended to
|
||||||
|
// encoded.
|
||||||
|
func (d *dataEncoder) encodeDataRaw(data []byte, dataMode dataMode, encoded *bitset.Bitset) {
|
||||||
|
modeIndicator := d.modeIndicator(dataMode)
|
||||||
|
charCountBits := d.charCountBits(dataMode)
|
||||||
|
|
||||||
|
// Append mode indicator.
|
||||||
|
encoded.Append(modeIndicator)
|
||||||
|
|
||||||
|
// Append character count.
|
||||||
|
encoded.AppendUint32(uint32(len(data)), charCountBits)
|
||||||
|
|
||||||
|
// Append data.
|
||||||
|
switch dataMode {
|
||||||
|
case dataModeNumeric:
|
||||||
|
for i := 0; i < len(data); i += 3 {
|
||||||
|
charsRemaining := len(data) - i
|
||||||
|
|
||||||
|
var value uint32
|
||||||
|
bitsUsed := 1
|
||||||
|
|
||||||
|
for j := 0; j < charsRemaining && j < 3; j++ {
|
||||||
|
value *= 10
|
||||||
|
value += uint32(data[i+j] - 0x30)
|
||||||
|
bitsUsed += 3
|
||||||
|
}
|
||||||
|
encoded.AppendUint32(value, bitsUsed)
|
||||||
|
}
|
||||||
|
case dataModeAlphanumeric:
|
||||||
|
for i := 0; i < len(data); i += 2 {
|
||||||
|
charsRemaining := len(data) - i
|
||||||
|
|
||||||
|
var value uint32
|
||||||
|
for j := 0; j < charsRemaining && j < 2; j++ {
|
||||||
|
value *= 45
|
||||||
|
value += encodeAlphanumericCharacter(data[i+j])
|
||||||
|
}
|
||||||
|
|
||||||
|
bitsUsed := 6
|
||||||
|
if charsRemaining > 1 {
|
||||||
|
bitsUsed = 11
|
||||||
|
}
|
||||||
|
|
||||||
|
encoded.AppendUint32(value, bitsUsed)
|
||||||
|
}
|
||||||
|
case dataModeByte:
|
||||||
|
for _, b := range data {
|
||||||
|
encoded.AppendByte(b, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// modeIndicator returns the segment header bits for a segment of type dataMode.
|
||||||
|
func (d *dataEncoder) modeIndicator(dataMode dataMode) *bitset.Bitset {
|
||||||
|
switch dataMode {
|
||||||
|
case dataModeNumeric:
|
||||||
|
return d.numericModeIndicator
|
||||||
|
case dataModeAlphanumeric:
|
||||||
|
return d.alphanumericModeIndicator
|
||||||
|
case dataModeByte:
|
||||||
|
return d.byteModeIndicator
|
||||||
|
default:
|
||||||
|
log.Panic("Unknown data mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// charCountBits returns the number of bits used to encode the length of a data
|
||||||
|
// segment of type dataMode.
|
||||||
|
func (d *dataEncoder) charCountBits(dataMode dataMode) int {
|
||||||
|
switch dataMode {
|
||||||
|
case dataModeNumeric:
|
||||||
|
return d.numNumericCharCountBits
|
||||||
|
case dataModeAlphanumeric:
|
||||||
|
return d.numAlphanumericCharCountBits
|
||||||
|
case dataModeByte:
|
||||||
|
return d.numByteCharCountBits
|
||||||
|
default:
|
||||||
|
log.Panic("Unknown data mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodedLength returns the number of bits required to encode n symbols in
|
||||||
|
// dataMode.
|
||||||
|
//
|
||||||
|
// The number of bits required is affected by:
|
||||||
|
// - QR code type - Mode Indicator length.
|
||||||
|
// - Data mode - number of bits used to represent data length.
|
||||||
|
// - Data mode - how the data is encoded.
|
||||||
|
// - Number of symbols encoded.
|
||||||
|
//
|
||||||
|
// An error is returned if the mode is not supported, or the length requested is
|
||||||
|
// too long to be represented.
|
||||||
|
func (d *dataEncoder) encodedLength(dataMode dataMode, n int) (int, error) {
|
||||||
|
modeIndicator := d.modeIndicator(dataMode)
|
||||||
|
charCountBits := d.charCountBits(dataMode)
|
||||||
|
|
||||||
|
if modeIndicator == nil {
|
||||||
|
return 0, errors.New("mode not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
maxLength := (1 << uint8(charCountBits)) - 1
|
||||||
|
|
||||||
|
if n > maxLength {
|
||||||
|
return 0, errors.New("length too long to be represented")
|
||||||
|
}
|
||||||
|
|
||||||
|
length := modeIndicator.Len() + charCountBits
|
||||||
|
|
||||||
|
switch dataMode {
|
||||||
|
case dataModeNumeric:
|
||||||
|
length += 10 * (n / 3)
|
||||||
|
|
||||||
|
if n%3 != 0 {
|
||||||
|
length += 1 + 3*(n%3)
|
||||||
|
}
|
||||||
|
case dataModeAlphanumeric:
|
||||||
|
length += 11 * (n / 2)
|
||||||
|
length += 6 * (n % 2)
|
||||||
|
case dataModeByte:
|
||||||
|
length += 8 * n
|
||||||
|
}
|
||||||
|
|
||||||
|
return length, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeAlphanumericChar returns the QR Code encoded value of v.
|
||||||
|
//
|
||||||
|
// v must be a QR Code defined alphanumeric character: 0-9, A-Z, SP, $%*+-./ or
|
||||||
|
// :. The characters are mapped to values in the range 0-44 respectively.
|
||||||
|
func encodeAlphanumericCharacter(v byte) uint32 {
|
||||||
|
c := uint32(v)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case c >= '0' && c <= '9':
|
||||||
|
// 0-9 encoded as 0-9.
|
||||||
|
return c - '0'
|
||||||
|
case c >= 'A' && c <= 'Z':
|
||||||
|
// A-Z encoded as 10-35.
|
||||||
|
return c - 'A' + 10
|
||||||
|
case c == ' ':
|
||||||
|
return 36
|
||||||
|
case c == '$':
|
||||||
|
return 37
|
||||||
|
case c == '%':
|
||||||
|
return 38
|
||||||
|
case c == '*':
|
||||||
|
return 39
|
||||||
|
case c == '+':
|
||||||
|
return 40
|
||||||
|
case c == '-':
|
||||||
|
return 41
|
||||||
|
case c == '.':
|
||||||
|
return 42
|
||||||
|
case c == '/':
|
||||||
|
return 43
|
||||||
|
case c == ':':
|
||||||
|
return 44
|
||||||
|
default:
|
||||||
|
log.Panicf("encodeAlphanumericCharacter() with non alphanumeric char %v.", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
328
vendor/github.com/skip2/go-qrcode/encoder_test.go
generated
vendored
Normal file
328
vendor/github.com/skip2/go-qrcode/encoder_test.go
generated
vendored
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClassifyDataMode(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
data []byte
|
||||||
|
actual []segment
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
[]byte{0x30},
|
||||||
|
[]segment{
|
||||||
|
{
|
||||||
|
dataModeNumeric,
|
||||||
|
[]byte{0x30},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]byte{0x30, 0x41, 0x42, 0x43, 0x20, 0x00, 0xf0, 0xf1, 0xf2, 0x31},
|
||||||
|
[]segment{
|
||||||
|
{
|
||||||
|
dataModeNumeric,
|
||||||
|
[]byte{0x30},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataModeAlphanumeric,
|
||||||
|
[]byte{0x41, 0x42, 0x43, 0x20},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataModeByte,
|
||||||
|
[]byte{0x00, 0xf0, 0xf1, 0xf2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataModeNumeric,
|
||||||
|
[]byte{0x31},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
encoder := newDataEncoder(dataEncoderType1To9)
|
||||||
|
encoder.encode(test.data)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(test.actual, encoder.actual) {
|
||||||
|
t.Errorf("Got %v, expected %v", encoder.actual, test.actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestByteModeLengthCalculations(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
dataEncoderType dataEncoderType
|
||||||
|
dataMode dataMode
|
||||||
|
numSymbols int
|
||||||
|
expectedLength int
|
||||||
|
}{}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
encoder := newDataEncoder(test.dataEncoderType)
|
||||||
|
var resultLength int
|
||||||
|
|
||||||
|
resultLength, err := encoder.encodedLength(test.dataMode, test.numSymbols)
|
||||||
|
|
||||||
|
if test.expectedLength == -1 {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Test %d: got length %d, expected error", i, resultLength)
|
||||||
|
}
|
||||||
|
} else if resultLength != test.expectedLength {
|
||||||
|
t.Errorf("Test %d: got length %d, expected length %d", i, resultLength,
|
||||||
|
test.expectedLength)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSingleModeEncodings(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
dataEncoderType dataEncoderType
|
||||||
|
dataMode dataMode
|
||||||
|
data string
|
||||||
|
expected *bitset.Bitset
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
dataEncoderType1To9,
|
||||||
|
dataModeNumeric,
|
||||||
|
"01234567",
|
||||||
|
bitset.NewFromBase2String("0001 0000001000 0000001100 0101011001 1000011"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataEncoderType1To9,
|
||||||
|
dataModeAlphanumeric,
|
||||||
|
"AC-42",
|
||||||
|
bitset.NewFromBase2String("0010 000000101 00111001110 11100111001 000010"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataEncoderType1To9,
|
||||||
|
dataModeByte,
|
||||||
|
"123",
|
||||||
|
bitset.NewFromBase2String("0100 00000011 00110001 00110010 00110011"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataEncoderType10To26,
|
||||||
|
dataModeByte,
|
||||||
|
"123",
|
||||||
|
bitset.NewFromBase2String("0100 00000000 00000011 00110001 00110010 00110011"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataEncoderType27To40,
|
||||||
|
dataModeByte,
|
||||||
|
"123",
|
||||||
|
bitset.NewFromBase2String("0100 00000000 00000011 00110001 00110010 00110011"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
encoder := newDataEncoder(test.dataEncoderType)
|
||||||
|
encoded := bitset.New()
|
||||||
|
|
||||||
|
encoder.encodeDataRaw([]byte(test.data), test.dataMode, encoded)
|
||||||
|
|
||||||
|
if !test.expected.Equals(encoded) {
|
||||||
|
t.Errorf("For %s got %s, expected %s", test.data, encoded.String(),
|
||||||
|
test.expected.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testModeSegment struct {
|
||||||
|
dataMode dataMode
|
||||||
|
numChars int
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOptimiseEncoding(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
dataEncoderType dataEncoderType
|
||||||
|
actual []testModeSegment
|
||||||
|
optimised []testModeSegment
|
||||||
|
}{
|
||||||
|
// Coalescing multiple segments.
|
||||||
|
{
|
||||||
|
dataEncoderType1To9,
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeAlphanumeric, 1}, // length = 4 + 9 + 6 = 19 bits
|
||||||
|
{dataModeNumeric, 1}, // length = 4 + 10 + 4 = 18 bits
|
||||||
|
{dataModeAlphanumeric, 1}, // 19 bits.
|
||||||
|
{dataModeNumeric, 1}, // 18 bits.
|
||||||
|
{dataModeAlphanumeric, 1}, // 19 bits.
|
||||||
|
// total = 93 bits.
|
||||||
|
},
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeAlphanumeric, 5}, // length = 4 + 9 + 22 + 6 = 41.
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Coalesing not necessary.
|
||||||
|
{
|
||||||
|
dataEncoderType1To9,
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeAlphanumeric, 1},
|
||||||
|
{dataModeNumeric, 20},
|
||||||
|
},
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeAlphanumeric, 1},
|
||||||
|
{dataModeNumeric, 20},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Switch to more general dataMode.
|
||||||
|
{
|
||||||
|
dataEncoderType1To9,
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeAlphanumeric, 1},
|
||||||
|
{dataModeByte, 1},
|
||||||
|
{dataModeNumeric, 1},
|
||||||
|
},
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeAlphanumeric, 1},
|
||||||
|
{dataModeByte, 2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// https://www.google.com/123
|
||||||
|
// BBBBBAAABBBABBBBBBABBBANNN
|
||||||
|
{
|
||||||
|
dataEncoderType1To9,
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeByte, 5},
|
||||||
|
{dataModeAlphanumeric, 3},
|
||||||
|
{dataModeByte, 3},
|
||||||
|
{dataModeAlphanumeric, 1},
|
||||||
|
{dataModeByte, 6},
|
||||||
|
{dataModeAlphanumeric, 1},
|
||||||
|
{dataModeAlphanumeric, 4},
|
||||||
|
{dataModeNumeric, 3},
|
||||||
|
},
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeByte, 23},
|
||||||
|
{dataModeNumeric, 3},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// HTTPS://WWW.GOOGLE.COM/123
|
||||||
|
// AAAAAAAAAAAAAAAAAAAAAAANNN
|
||||||
|
{
|
||||||
|
dataEncoderType1To9,
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeAlphanumeric, 23},
|
||||||
|
{dataModeNumeric, 3},
|
||||||
|
},
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeAlphanumeric, 26},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataEncoderType27To40,
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeByte, 1},
|
||||||
|
{dataModeNumeric, 1},
|
||||||
|
{dataModeByte, 1},
|
||||||
|
{dataModeNumeric, 1},
|
||||||
|
{dataModeByte, 1},
|
||||||
|
{dataModeNumeric, 1},
|
||||||
|
{dataModeByte, 1},
|
||||||
|
{dataModeNumeric, 1},
|
||||||
|
},
|
||||||
|
[]testModeSegment{
|
||||||
|
{dataModeByte, 8},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
numTotalChars := 0
|
||||||
|
for _, v := range test.actual {
|
||||||
|
numTotalChars += v.numChars
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make([]byte, numTotalChars)
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for _, v := range test.actual {
|
||||||
|
for j := 0; j < v.numChars; j++ {
|
||||||
|
switch v.dataMode {
|
||||||
|
case dataModeNumeric:
|
||||||
|
data[i] = '1'
|
||||||
|
case dataModeAlphanumeric:
|
||||||
|
data[i] = 'A'
|
||||||
|
case dataModeByte:
|
||||||
|
data[i] = '#'
|
||||||
|
default:
|
||||||
|
t.Fatal("Unrecognised data mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder := newDataEncoder(test.dataEncoderType)
|
||||||
|
|
||||||
|
_, err := encoder.encode(data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Got %s, expected valid encoding", err.Error())
|
||||||
|
} else {
|
||||||
|
ok := true
|
||||||
|
|
||||||
|
if len(encoder.optimised) != len(test.optimised) {
|
||||||
|
ok = false
|
||||||
|
} else {
|
||||||
|
for i, s := range test.optimised {
|
||||||
|
if encoder.optimised[i].dataMode != s.dataMode ||
|
||||||
|
len(encoder.optimised[i].data) != s.numChars {
|
||||||
|
ok = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("got %s, expected %s", segmentsString(encoder.optimised),
|
||||||
|
testModeSegmentsString(test.optimised))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testModeSegmentsString(segments []testModeSegment) string {
|
||||||
|
result := "["
|
||||||
|
|
||||||
|
for i, segment := range segments {
|
||||||
|
if i > 0 {
|
||||||
|
result += ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
result += fmt.Sprintf("%d*%s", segment.numChars,
|
||||||
|
dataModeString(segment.dataMode))
|
||||||
|
}
|
||||||
|
|
||||||
|
result += "]"
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func segmentsString(segments []segment) string {
|
||||||
|
result := "["
|
||||||
|
|
||||||
|
for i, segment := range segments {
|
||||||
|
if i > 0 {
|
||||||
|
result += ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
result += fmt.Sprintf("%d*%s", len(segment.data),
|
||||||
|
dataModeString(segment.dataMode))
|
||||||
|
}
|
||||||
|
|
||||||
|
result += "]"
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
31
vendor/github.com/skip2/go-qrcode/example_test.go
generated
vendored
Normal file
31
vendor/github.com/skip2/go-qrcode/example_test.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
/*
|
||||||
|
Amendments Thu, 2017-December-14:
|
||||||
|
- test integration (go test -v)
|
||||||
|
- idiomatic go code
|
||||||
|
*/
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExampleEncode(t *testing.T) {
|
||||||
|
if png, err := Encode("https://example.org", Medium, 256); err != nil {
|
||||||
|
t.Errorf("Error: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
fmt.Printf("PNG is %d bytes long", len(png))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExampleWriteFile(t *testing.T) {
|
||||||
|
filename := "example.png"
|
||||||
|
if err := WriteFile("https://example.org", Medium, 256, filename); err != nil {
|
||||||
|
if err = os.Remove(filename); err != nil {
|
||||||
|
t.Errorf("Error: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
554
vendor/github.com/skip2/go-qrcode/qrcode.go
generated
vendored
Normal file
554
vendor/github.com/skip2/go-qrcode/qrcode.go
generated
vendored
Normal file
@ -0,0 +1,554 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package qrcode implements a QR Code encoder.
|
||||||
|
|
||||||
|
A QR Code is a matrix (two-dimensional) barcode. Arbitrary content may be
|
||||||
|
encoded.
|
||||||
|
|
||||||
|
A QR Code contains error recovery information to aid reading damaged or
|
||||||
|
obscured codes. There are four levels of error recovery: qrcode.{Low, Medium,
|
||||||
|
High, Highest}. QR Codes with a higher recovery level are more robust to damage,
|
||||||
|
at the cost of being physically larger.
|
||||||
|
|
||||||
|
Three functions cover most use cases:
|
||||||
|
|
||||||
|
- Create a PNG image:
|
||||||
|
|
||||||
|
var png []byte
|
||||||
|
png, err := qrcode.Encode("https://example.org", qrcode.Medium, 256)
|
||||||
|
|
||||||
|
- Create a PNG image and write to a file:
|
||||||
|
|
||||||
|
err := qrcode.WriteFile("https://example.org", qrcode.Medium, 256, "qr.png")
|
||||||
|
|
||||||
|
- Create a PNG image with custom colors and write to file:
|
||||||
|
|
||||||
|
err := qrcode.WriteColorFile("https://example.org", qrcode.Medium, 256, color.Black, color.White, "qr.png")
|
||||||
|
|
||||||
|
All examples use the qrcode.Medium error Recovery Level and create a fixed
|
||||||
|
256x256px size QR Code. The last function creates a white on black instead of black
|
||||||
|
on white QR Code.
|
||||||
|
|
||||||
|
To generate a variable sized image instead, specify a negative size (in place of
|
||||||
|
the 256 above), such as -4 or -5. Larger negative numbers create larger images:
|
||||||
|
A size of -5 sets each module (QR Code "pixel") to be 5px wide/high.
|
||||||
|
|
||||||
|
- Create a PNG image (variable size, with minimum white padding) and write to a file:
|
||||||
|
|
||||||
|
err := qrcode.WriteFile("https://example.org", qrcode.Medium, -5, "qr.png")
|
||||||
|
|
||||||
|
The maximum capacity of a QR Code varies according to the content encoded and
|
||||||
|
the error recovery level. The maximum capacity is 2,953 bytes, 4,296
|
||||||
|
alphanumeric characters, 7,089 numeric digits, or a combination of these.
|
||||||
|
|
||||||
|
This package implements a subset of QR Code 2005, as defined in ISO/IEC
|
||||||
|
18004:2006.
|
||||||
|
*/
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/png"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||||||
|
reedsolomon "github.com/skip2/go-qrcode/reedsolomon"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Encode a QR Code and return a raw PNG image.
|
||||||
|
//
|
||||||
|
// size is both the image width and height in pixels. If size is too small then
|
||||||
|
// a larger image is silently returned. Negative values for size cause a
|
||||||
|
// variable sized image to be returned: See the documentation for Image().
|
||||||
|
//
|
||||||
|
// To serve over HTTP, remember to send a Content-Type: image/png header.
|
||||||
|
func Encode(content string, level RecoveryLevel, size int) ([]byte, error) {
|
||||||
|
var q *QRCode
|
||||||
|
|
||||||
|
q, err := New(content, level)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.PNG(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteFile encodes, then writes a QR Code to the given filename in PNG format.
|
||||||
|
//
|
||||||
|
// size is both the image width and height in pixels. If size is too small then
|
||||||
|
// a larger image is silently written. Negative values for size cause a variable
|
||||||
|
// sized image to be written: See the documentation for Image().
|
||||||
|
func WriteFile(content string, level RecoveryLevel, size int, filename string) error {
|
||||||
|
var q *QRCode
|
||||||
|
|
||||||
|
q, err := New(content, level)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.WriteFile(size, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteColorFile encodes, then writes a QR Code to the given filename in PNG format.
|
||||||
|
// With WriteColorFile you can also specify the colors you want to use.
|
||||||
|
//
|
||||||
|
// size is both the image width and height in pixels. If size is too small then
|
||||||
|
// a larger image is silently written. Negative values for size cause a variable
|
||||||
|
// sized image to be written: See the documentation for Image().
|
||||||
|
func WriteColorFile(content string, level RecoveryLevel, size int, background,
|
||||||
|
foreground color.Color, filename string) error {
|
||||||
|
|
||||||
|
var q *QRCode
|
||||||
|
|
||||||
|
q, err := New(content, level)
|
||||||
|
|
||||||
|
q.BackgroundColor = background
|
||||||
|
q.ForegroundColor = foreground
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.WriteFile(size, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A QRCode represents a valid encoded QRCode.
|
||||||
|
type QRCode struct {
|
||||||
|
// Original content encoded.
|
||||||
|
Content string
|
||||||
|
|
||||||
|
// QR Code type.
|
||||||
|
Level RecoveryLevel
|
||||||
|
VersionNumber int
|
||||||
|
|
||||||
|
// User settable drawing options.
|
||||||
|
ForegroundColor color.Color
|
||||||
|
BackgroundColor color.Color
|
||||||
|
|
||||||
|
encoder *dataEncoder
|
||||||
|
version qrCodeVersion
|
||||||
|
|
||||||
|
data *bitset.Bitset
|
||||||
|
symbol *symbol
|
||||||
|
mask int
|
||||||
|
}
|
||||||
|
|
||||||
|
// New constructs a QRCode.
|
||||||
|
//
|
||||||
|
// var q *qrcode.QRCode
|
||||||
|
// q, err := qrcode.New("my content", qrcode.Medium)
|
||||||
|
//
|
||||||
|
// An error occurs if the content is too long.
|
||||||
|
func New(content string, level RecoveryLevel) (*QRCode, error) {
|
||||||
|
encoders := []dataEncoderType{dataEncoderType1To9, dataEncoderType10To26,
|
||||||
|
dataEncoderType27To40}
|
||||||
|
|
||||||
|
var encoder *dataEncoder
|
||||||
|
var encoded *bitset.Bitset
|
||||||
|
var chosenVersion *qrCodeVersion
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for _, t := range encoders {
|
||||||
|
encoder = newDataEncoder(t)
|
||||||
|
encoded, err = encoder.encode([]byte(content))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
chosenVersion = chooseQRCodeVersion(level, encoder, encoded.Len())
|
||||||
|
|
||||||
|
if chosenVersion != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if chosenVersion == nil {
|
||||||
|
return nil, errors.New("content too long to encode")
|
||||||
|
}
|
||||||
|
|
||||||
|
q := &QRCode{
|
||||||
|
Content: content,
|
||||||
|
|
||||||
|
Level: level,
|
||||||
|
VersionNumber: chosenVersion.version,
|
||||||
|
|
||||||
|
ForegroundColor: color.Black,
|
||||||
|
BackgroundColor: color.White,
|
||||||
|
|
||||||
|
encoder: encoder,
|
||||||
|
data: encoded,
|
||||||
|
version: *chosenVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len()))
|
||||||
|
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QRCode, error) {
|
||||||
|
var encoder *dataEncoder
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case version >= 1 && version <= 9:
|
||||||
|
encoder = newDataEncoder(dataEncoderType1To9)
|
||||||
|
case version >= 10 && version <= 26:
|
||||||
|
encoder = newDataEncoder(dataEncoderType10To26)
|
||||||
|
case version >= 27 && version <= 40:
|
||||||
|
encoder = newDataEncoder(dataEncoderType27To40)
|
||||||
|
default:
|
||||||
|
log.Fatalf("Invalid version %d (expected 1-40 inclusive)", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
var encoded *bitset.Bitset
|
||||||
|
encoded, err := encoder.encode([]byte(content))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
chosenVersion := getQRCodeVersion(level, version)
|
||||||
|
|
||||||
|
if chosenVersion == nil {
|
||||||
|
return nil, errors.New("cannot find QR Code version")
|
||||||
|
}
|
||||||
|
|
||||||
|
q := &QRCode{
|
||||||
|
Content: content,
|
||||||
|
|
||||||
|
Level: level,
|
||||||
|
VersionNumber: chosenVersion.version,
|
||||||
|
|
||||||
|
ForegroundColor: color.Black,
|
||||||
|
BackgroundColor: color.White,
|
||||||
|
|
||||||
|
encoder: encoder,
|
||||||
|
data: encoded,
|
||||||
|
version: *chosenVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len()))
|
||||||
|
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bitmap returns the QR Code as a 2D array of 1-bit pixels.
|
||||||
|
//
|
||||||
|
// bitmap[y][x] is true if the pixel at (x, y) is set.
|
||||||
|
//
|
||||||
|
// The bitmap includes the required "quiet zone" around the QR Code to aid
|
||||||
|
// decoding.
|
||||||
|
func (q *QRCode) Bitmap() [][]bool {
|
||||||
|
return q.symbol.bitmap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image returns the QR Code as an image.Image.
|
||||||
|
//
|
||||||
|
// A positive size sets a fixed image width and height (e.g. 256 yields an
|
||||||
|
// 256x256px image).
|
||||||
|
//
|
||||||
|
// Depending on the amount of data encoded, fixed size images can have different
|
||||||
|
// amounts of padding (white space around the QR Code). As an alternative, a
|
||||||
|
// variable sized image can be generated instead:
|
||||||
|
//
|
||||||
|
// A negative size causes a variable sized image to be returned. The image
|
||||||
|
// returned is the minimum size required for the QR Code. Choose a larger
|
||||||
|
// negative number to increase the scale of the image. e.g. a size of -5 causes
|
||||||
|
// each module (QR Code "pixel") to be 5px in size.
|
||||||
|
func (q *QRCode) Image(size int) image.Image {
|
||||||
|
// Minimum pixels (both width and height) required.
|
||||||
|
realSize := q.symbol.size
|
||||||
|
|
||||||
|
// Variable size support.
|
||||||
|
if size < 0 {
|
||||||
|
size = size * -1 * realSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual pixels available to draw the symbol. Automatically increase the
|
||||||
|
// image size if it's not large enough.
|
||||||
|
if size < realSize {
|
||||||
|
size = realSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size of each module drawn.
|
||||||
|
pixelsPerModule := size / realSize
|
||||||
|
|
||||||
|
// Center the symbol within the image.
|
||||||
|
offset := (size - realSize*pixelsPerModule) / 2
|
||||||
|
|
||||||
|
rect := image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{size, size}}
|
||||||
|
|
||||||
|
// Saves a few bytes to have them in this order
|
||||||
|
p := color.Palette([]color.Color{q.BackgroundColor, q.ForegroundColor})
|
||||||
|
img := image.NewPaletted(rect, p)
|
||||||
|
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
for j := 0; j < size; j++ {
|
||||||
|
img.Set(i, j, q.BackgroundColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap := q.symbol.bitmap()
|
||||||
|
for y, row := range bitmap {
|
||||||
|
for x, v := range row {
|
||||||
|
if v {
|
||||||
|
startX := x*pixelsPerModule + offset
|
||||||
|
startY := y*pixelsPerModule + offset
|
||||||
|
for i := startX; i < startX+pixelsPerModule; i++ {
|
||||||
|
for j := startY; j < startY+pixelsPerModule; j++ {
|
||||||
|
img.Set(i, j, q.ForegroundColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
|
// PNG returns the QR Code as a PNG image.
|
||||||
|
//
|
||||||
|
// size is both the image width and height in pixels. If size is too small then
|
||||||
|
// a larger image is silently returned. Negative values for size cause a
|
||||||
|
// variable sized image to be returned: See the documentation for Image().
|
||||||
|
func (q *QRCode) PNG(size int) ([]byte, error) {
|
||||||
|
img := q.Image(size)
|
||||||
|
|
||||||
|
encoder := png.Encoder{CompressionLevel: png.BestCompression}
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
err := encoder.Encode(&b, img)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes the QR Code as a PNG image to io.Writer.
|
||||||
|
//
|
||||||
|
// size is both the image width and height in pixels. If size is too small then
|
||||||
|
// a larger image is silently written. Negative values for size cause a
|
||||||
|
// variable sized image to be written: See the documentation for Image().
|
||||||
|
func (q *QRCode) Write(size int, out io.Writer) error {
|
||||||
|
var png []byte
|
||||||
|
|
||||||
|
png, err := q.PNG(size)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = out.Write(png)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteFile writes the QR Code as a PNG image to the specified file.
|
||||||
|
//
|
||||||
|
// size is both the image width and height in pixels. If size is too small then
|
||||||
|
// a larger image is silently written. Negative values for size cause a
|
||||||
|
// variable sized image to be written: See the documentation for Image().
|
||||||
|
func (q *QRCode) WriteFile(size int, filename string) error {
|
||||||
|
var png []byte
|
||||||
|
|
||||||
|
png, err := q.PNG(size)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(filename, png, os.FileMode(0644))
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode completes the steps required to encode the QR Code. These include
|
||||||
|
// adding the terminator bits and padding, splitting the data into blocks and
|
||||||
|
// applying the error correction, and selecting the best data mask.
|
||||||
|
func (q *QRCode) encode(numTerminatorBits int) {
|
||||||
|
q.addTerminatorBits(numTerminatorBits)
|
||||||
|
q.addPadding()
|
||||||
|
|
||||||
|
encoded := q.encodeBlocks()
|
||||||
|
|
||||||
|
const numMasks int = 8
|
||||||
|
penalty := 0
|
||||||
|
|
||||||
|
for mask := 0; mask < numMasks; mask++ {
|
||||||
|
var s *symbol
|
||||||
|
var err error
|
||||||
|
|
||||||
|
s, err = buildRegularSymbol(q.version, mask, encoded)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
numEmptyModules := s.numEmptyModules()
|
||||||
|
if numEmptyModules != 0 {
|
||||||
|
log.Panicf("bug: numEmptyModules is %d (expected 0) (version=%d)",
|
||||||
|
numEmptyModules, q.VersionNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := s.penaltyScore()
|
||||||
|
|
||||||
|
//log.Printf("mask=%d p=%3d p1=%3d p2=%3d p3=%3d p4=%d\n", mask, p, s.penalty1(), s.penalty2(), s.penalty3(), s.penalty4())
|
||||||
|
|
||||||
|
if q.symbol == nil || p < penalty {
|
||||||
|
q.symbol = s
|
||||||
|
q.mask = mask
|
||||||
|
penalty = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// addTerminatorBits adds final terminator bits to the encoded data.
|
||||||
|
//
|
||||||
|
// The number of terminator bits required is determined when the QR Code version
|
||||||
|
// is chosen (which itself depends on the length of the data encoded). The
|
||||||
|
// terminator bits are thus added after the QR Code version
|
||||||
|
// is chosen, rather than at the data encoding stage.
|
||||||
|
func (q *QRCode) addTerminatorBits(numTerminatorBits int) {
|
||||||
|
q.data.AppendNumBools(numTerminatorBits, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeBlocks takes the completed (terminated & padded) encoded data, splits
|
||||||
|
// the data into blocks (as specified by the QR Code version), applies error
|
||||||
|
// correction to each block, then interleaves the blocks together.
|
||||||
|
//
|
||||||
|
// The QR Code's final data sequence is returned.
|
||||||
|
func (q *QRCode) encodeBlocks() *bitset.Bitset {
|
||||||
|
// Split into blocks.
|
||||||
|
type dataBlock struct {
|
||||||
|
data *bitset.Bitset
|
||||||
|
ecStartOffset int
|
||||||
|
}
|
||||||
|
|
||||||
|
block := make([]dataBlock, q.version.numBlocks())
|
||||||
|
|
||||||
|
start := 0
|
||||||
|
end := 0
|
||||||
|
blockID := 0
|
||||||
|
|
||||||
|
for _, b := range q.version.block {
|
||||||
|
for j := 0; j < b.numBlocks; j++ {
|
||||||
|
start = end
|
||||||
|
end = start + b.numDataCodewords*8
|
||||||
|
|
||||||
|
// Apply error correction to each block.
|
||||||
|
numErrorCodewords := b.numCodewords - b.numDataCodewords
|
||||||
|
block[blockID].data = reedsolomon.Encode(q.data.Substr(start, end), numErrorCodewords)
|
||||||
|
block[blockID].ecStartOffset = end - start
|
||||||
|
|
||||||
|
blockID++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interleave the blocks.
|
||||||
|
|
||||||
|
result := bitset.New()
|
||||||
|
|
||||||
|
// Combine data blocks.
|
||||||
|
working := true
|
||||||
|
for i := 0; working; i += 8 {
|
||||||
|
working = false
|
||||||
|
|
||||||
|
for j, b := range block {
|
||||||
|
if i >= block[j].ecStartOffset {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Append(b.data.Substr(i, i+8))
|
||||||
|
|
||||||
|
working = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine error correction blocks.
|
||||||
|
working = true
|
||||||
|
for i := 0; working; i += 8 {
|
||||||
|
working = false
|
||||||
|
|
||||||
|
for j, b := range block {
|
||||||
|
offset := i + block[j].ecStartOffset
|
||||||
|
if offset >= block[j].data.Len() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Append(b.data.Substr(offset, offset+8))
|
||||||
|
|
||||||
|
working = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append remainder bits.
|
||||||
|
result.AppendNumBools(q.version.numRemainderBits, false)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// max returns the maximum of a and b.
|
||||||
|
func max(a int, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// addPadding pads the encoded data upto the full length required.
|
||||||
|
func (q *QRCode) addPadding() {
|
||||||
|
numDataBits := q.version.numDataBits()
|
||||||
|
|
||||||
|
if q.data.Len() == numDataBits {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pad to the nearest codeword boundary.
|
||||||
|
q.data.AppendNumBools(q.version.numBitsToPadToCodeword(q.data.Len()), false)
|
||||||
|
|
||||||
|
// Pad codewords 0b11101100 and 0b00010001.
|
||||||
|
padding := [2]*bitset.Bitset{
|
||||||
|
bitset.New(true, true, true, false, true, true, false, false),
|
||||||
|
bitset.New(false, false, false, true, false, false, false, true),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert pad codewords alternately.
|
||||||
|
i := 0
|
||||||
|
for numDataBits-q.data.Len() >= 8 {
|
||||||
|
q.data.Append(padding[i])
|
||||||
|
|
||||||
|
i = 1 - i // Alternate between 0 and 1.
|
||||||
|
}
|
||||||
|
|
||||||
|
if q.data.Len() != numDataBits {
|
||||||
|
log.Panicf("BUG: got len %d, expected %d", q.data.Len(), numDataBits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToString produces a multi-line string that forms a QR-code image.
|
||||||
|
func (q *QRCode) ToString(inverseColor bool) string {
|
||||||
|
bits := q.Bitmap()
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for y := range bits {
|
||||||
|
for x := range bits[y] {
|
||||||
|
if bits[y][x] != inverseColor {
|
||||||
|
buf.WriteString(" ")
|
||||||
|
} else {
|
||||||
|
buf.WriteString("██")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
85
vendor/github.com/skip2/go-qrcode/qrcode/main.go
generated
vendored
Normal file
85
vendor/github.com/skip2/go-qrcode/qrcode/main.go
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
qrcode "github.com/skip2/go-qrcode"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
outFile := flag.String("o", "", "out PNG file prefix, empty for stdout")
|
||||||
|
size := flag.Int("s", 256, "image size (pixel)")
|
||||||
|
textArt := flag.Bool("t", false, "print as text-art on stdout")
|
||||||
|
negative := flag.Bool("i", false, "invert black and white")
|
||||||
|
flag.Usage = func() {
|
||||||
|
fmt.Fprintf(os.Stderr, `qrcode -- QR Code encoder in Go
|
||||||
|
https://github.com/skip2/go-qrcode
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
`)
|
||||||
|
flag.PrintDefaults()
|
||||||
|
fmt.Fprintf(os.Stderr, `
|
||||||
|
Usage:
|
||||||
|
1. Arguments except for flags are joined by " " and used to generate QR code.
|
||||||
|
Default output is STDOUT, pipe to imagemagick command "display" to display
|
||||||
|
on any X server.
|
||||||
|
|
||||||
|
qrcode hello word | display
|
||||||
|
|
||||||
|
2. Save to file if "display" not available:
|
||||||
|
|
||||||
|
qrcode "homepage: https://github.com/skip2/go-qrcode" > out.png
|
||||||
|
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if len(flag.Args()) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
checkError(fmt.Errorf("Error: no content given"))
|
||||||
|
}
|
||||||
|
|
||||||
|
content := strings.Join(flag.Args(), " ")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var q *qrcode.QRCode
|
||||||
|
q, err = qrcode.New(content, qrcode.Highest)
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
if *textArt {
|
||||||
|
art := q.ToString(*negative)
|
||||||
|
fmt.Println(art)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if *negative {
|
||||||
|
q.ForegroundColor, q.BackgroundColor = q.BackgroundColor, q.ForegroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
var png []byte
|
||||||
|
png, err = q.PNG(*size)
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
if *outFile == "" {
|
||||||
|
os.Stdout.Write(png)
|
||||||
|
} else {
|
||||||
|
var fh *os.File
|
||||||
|
fh, err = os.Create(*outFile + ".png")
|
||||||
|
checkError(err)
|
||||||
|
defer fh.Close()
|
||||||
|
fh.Write(png)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkError(err error) {
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
232
vendor/github.com/skip2/go-qrcode/qrcode_decode_test.go
generated
vendored
Normal file
232
vendor/github.com/skip2/go-qrcode/qrcode_decode_test.go
generated
vendored
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These tests use zbarimg to decode generated QR Codes to ensure they are
|
||||||
|
// readable. sudo apt-get install zbar-tools, or download from
|
||||||
|
// http://zbar.sourceforge.net.
|
||||||
|
//
|
||||||
|
// By default these tests are disabled to avoid a dependency on zbarimg if
|
||||||
|
// you're not running the tests. Use the -test-decode flag (go test
|
||||||
|
// -test-decode) to enable.
|
||||||
|
|
||||||
|
var testDecode *bool = flag.Bool("test-decode",
|
||||||
|
false,
|
||||||
|
"Enable decode tests. Requires zbarimg installed.")
|
||||||
|
|
||||||
|
var testDecodeFuzz *bool = flag.Bool("test-decode-fuzz",
|
||||||
|
false,
|
||||||
|
"Enable decode fuzz tests. Requires zbarimg installed.")
|
||||||
|
|
||||||
|
func TestDecodeBasic(t *testing.T) {
|
||||||
|
if !*testDecode {
|
||||||
|
t.Skip("Decode tests not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
content string
|
||||||
|
numRepetitions int
|
||||||
|
level RecoveryLevel
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"A",
|
||||||
|
1,
|
||||||
|
Low,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"A",
|
||||||
|
1,
|
||||||
|
Medium,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"A",
|
||||||
|
1,
|
||||||
|
High,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"A",
|
||||||
|
1,
|
||||||
|
Highest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"01234567",
|
||||||
|
1,
|
||||||
|
Medium,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
content := strings.Repeat(test.content, test.numRepetitions)
|
||||||
|
|
||||||
|
q, err := New(content, test.level)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zbarimgCheck(q)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeAllVersionLevels(t *testing.T) {
|
||||||
|
if !*testDecode {
|
||||||
|
t.Skip("Decode tests not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
for version := 1; version <= 40; version++ {
|
||||||
|
for _, level := range []RecoveryLevel{Low, Medium, High, Highest} {
|
||||||
|
t.Logf("Version=%d Level=%d",
|
||||||
|
version,
|
||||||
|
level)
|
||||||
|
|
||||||
|
q, err := newWithForcedVersion(
|
||||||
|
fmt.Sprintf("v-%d l-%d", version, level), version, level)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zbarimgCheck(q)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Version=%d Level=%d, err=%s, expected success",
|
||||||
|
version,
|
||||||
|
level,
|
||||||
|
err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeAllCharacters(t *testing.T) {
|
||||||
|
if !*testDecode {
|
||||||
|
t.Skip("Decode tests not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
var content string
|
||||||
|
|
||||||
|
// zbarimg has trouble with null bytes, hence start from ASCII 1.
|
||||||
|
for i := 1; i < 256; i++ {
|
||||||
|
content += string(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
q, err := New(content, Low)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zbarimgCheck(q)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeFuzz(t *testing.T) {
|
||||||
|
if !*testDecodeFuzz {
|
||||||
|
t.Skip("Decode fuzz tests not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := rand.New(rand.NewSource(0))
|
||||||
|
|
||||||
|
const iterations int = 32
|
||||||
|
const maxLength int = 128
|
||||||
|
|
||||||
|
for i := 0; i < iterations; i++ {
|
||||||
|
len := r.Intn(maxLength-1) + 1
|
||||||
|
|
||||||
|
var content string
|
||||||
|
for j := 0; j < len; j++ {
|
||||||
|
// zbarimg seems to have trouble with special characters, test printable
|
||||||
|
// characters only for now.
|
||||||
|
content += string(32 + r.Intn(94))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, level := range []RecoveryLevel{Low, Medium, High, Highest} {
|
||||||
|
q, err := New(content, level)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zbarimgCheck(q)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func zbarimgCheck(q *QRCode) error {
|
||||||
|
s, err := zbarimgDecode(q)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s != q.Content {
|
||||||
|
q.WriteFile(256, fmt.Sprintf("%x.png", q.Content))
|
||||||
|
return fmt.Errorf("got '%s' (%x) expected '%s' (%x)", s, s, q.Content, q.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func zbarimgDecode(q *QRCode) (string, error) {
|
||||||
|
var png []byte
|
||||||
|
|
||||||
|
// 512x512px
|
||||||
|
png, err := q.PNG(512)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("zbarimg", "--quiet", "-Sdisable",
|
||||||
|
"-Sqrcode.enable", "/dev/stdin")
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
|
||||||
|
cmd.Stdin = bytes.NewBuffer(png)
|
||||||
|
cmd.Stdout = &out
|
||||||
|
|
||||||
|
err = cmd.Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSuffix(strings.TrimPrefix(out.String(), "QR-Code:"), "\n"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeTest(b *testing.B) {
|
||||||
|
if !*testDecode {
|
||||||
|
b.Skip("Decode benchmarks not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
q, err := New("content", Medium)
|
||||||
|
if err != nil {
|
||||||
|
b.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zbarimgCheck(q)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
b.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
173
vendor/github.com/skip2/go-qrcode/qrcode_test.go
generated
vendored
Normal file
173
vendor/github.com/skip2/go-qrcode/qrcode_test.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestQRCodeMaxCapacity(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("Skipping TestQRCodeCapacity")
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
string string
|
||||||
|
numRepetitions int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"0",
|
||||||
|
7089,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"A",
|
||||||
|
4296,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"#",
|
||||||
|
2953,
|
||||||
|
},
|
||||||
|
// Alternate byte/numeric data types. Optimises to 2,952 bytes.
|
||||||
|
{
|
||||||
|
"#1",
|
||||||
|
1476,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
_, err := New(strings.Repeat(test.string, test.numRepetitions), Low)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d x '%s' got %s expected success", test.numRepetitions,
|
||||||
|
test.string, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
_, err := New(strings.Repeat(test.string, test.numRepetitions+1), Low)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("%d x '%s' chars encodable, expected not encodable",
|
||||||
|
test.numRepetitions+1, test.string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQRCodeVersionCapacity(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
version int
|
||||||
|
level RecoveryLevel
|
||||||
|
maxNumeric int
|
||||||
|
maxAlphanumeric int
|
||||||
|
maxByte int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
1,
|
||||||
|
Low,
|
||||||
|
41,
|
||||||
|
25,
|
||||||
|
17,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
2,
|
||||||
|
Low,
|
||||||
|
77,
|
||||||
|
47,
|
||||||
|
32,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
2,
|
||||||
|
Highest,
|
||||||
|
34,
|
||||||
|
20,
|
||||||
|
14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
40,
|
||||||
|
Low,
|
||||||
|
7089,
|
||||||
|
4296,
|
||||||
|
2953,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
40,
|
||||||
|
Highest,
|
||||||
|
3057,
|
||||||
|
1852,
|
||||||
|
1273,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
numericData := strings.Repeat("1", test.maxNumeric)
|
||||||
|
alphanumericData := strings.Repeat("A", test.maxAlphanumeric)
|
||||||
|
byteData := strings.Repeat("#", test.maxByte)
|
||||||
|
|
||||||
|
var n *QRCode
|
||||||
|
var a *QRCode
|
||||||
|
var b *QRCode
|
||||||
|
var err error
|
||||||
|
|
||||||
|
n, err = New(numericData, test.level)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
a, err = New(alphanumericData, test.level)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = New(byteData, test.level)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.VersionNumber != test.version {
|
||||||
|
t.Fatalf("Test #%d numeric has version #%d, expected #%d", i,
|
||||||
|
n.VersionNumber, test.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.VersionNumber != test.version {
|
||||||
|
t.Fatalf("Test #%d alphanumeric has version #%d, expected #%d", i,
|
||||||
|
a.VersionNumber, test.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.VersionNumber != test.version {
|
||||||
|
t.Fatalf("Test #%d byte has version #%d, expected #%d", i,
|
||||||
|
b.VersionNumber, test.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQRCodeISOAnnexIExample(t *testing.T) {
|
||||||
|
var q *QRCode
|
||||||
|
q, err := New("01234567", Medium)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error producing ISO Annex I Example: %s, expected success",
|
||||||
|
err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectedMask int = 2
|
||||||
|
|
||||||
|
if q.mask != 2 {
|
||||||
|
t.Errorf("ISO Annex I example mask got %d, expected %d\n", q.mask,
|
||||||
|
expectedMask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkQRCodeURLSize(b *testing.B) {
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
New("http://www.example.org", Medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkQRCodeMaximumSize(b *testing.B) {
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
// 7089 is the maximum encodable number of numeric digits.
|
||||||
|
New(strings.Repeat("0", 7089), Low)
|
||||||
|
}
|
||||||
|
}
|
387
vendor/github.com/skip2/go-qrcode/reedsolomon/gf2_8.go
generated
vendored
Normal file
387
vendor/github.com/skip2/go-qrcode/reedsolomon/gf2_8.go
generated
vendored
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package reedsolomon
|
||||||
|
|
||||||
|
// Addition, subtraction, multiplication, and division in GF(2^8).
|
||||||
|
// Operations are performed modulo x^8 + x^4 + x^3 + x^2 + 1.
|
||||||
|
|
||||||
|
// http://en.wikipedia.org/wiki/Finite_field_arithmetic
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
|
const (
|
||||||
|
gfZero = gfElement(0)
|
||||||
|
gfOne = gfElement(1)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
gfExpTable = [256]gfElement{
|
||||||
|
/* 0 - 9 */ 1, 2, 4, 8, 16, 32, 64, 128, 29, 58,
|
||||||
|
/* 10 - 19 */ 116, 232, 205, 135, 19, 38, 76, 152, 45, 90,
|
||||||
|
/* 20 - 29 */ 180, 117, 234, 201, 143, 3, 6, 12, 24, 48,
|
||||||
|
/* 30 - 39 */ 96, 192, 157, 39, 78, 156, 37, 74, 148, 53,
|
||||||
|
/* 40 - 49 */ 106, 212, 181, 119, 238, 193, 159, 35, 70, 140,
|
||||||
|
/* 50 - 59 */ 5, 10, 20, 40, 80, 160, 93, 186, 105, 210,
|
||||||
|
/* 60 - 69 */ 185, 111, 222, 161, 95, 190, 97, 194, 153, 47,
|
||||||
|
/* 70 - 79 */ 94, 188, 101, 202, 137, 15, 30, 60, 120, 240,
|
||||||
|
/* 80 - 89 */ 253, 231, 211, 187, 107, 214, 177, 127, 254, 225,
|
||||||
|
/* 90 - 99 */ 223, 163, 91, 182, 113, 226, 217, 175, 67, 134,
|
||||||
|
/* 100 - 109 */ 17, 34, 68, 136, 13, 26, 52, 104, 208, 189,
|
||||||
|
/* 110 - 119 */ 103, 206, 129, 31, 62, 124, 248, 237, 199, 147,
|
||||||
|
/* 120 - 129 */ 59, 118, 236, 197, 151, 51, 102, 204, 133, 23,
|
||||||
|
/* 130 - 139 */ 46, 92, 184, 109, 218, 169, 79, 158, 33, 66,
|
||||||
|
/* 140 - 149 */ 132, 21, 42, 84, 168, 77, 154, 41, 82, 164,
|
||||||
|
/* 150 - 159 */ 85, 170, 73, 146, 57, 114, 228, 213, 183, 115,
|
||||||
|
/* 160 - 169 */ 230, 209, 191, 99, 198, 145, 63, 126, 252, 229,
|
||||||
|
/* 170 - 179 */ 215, 179, 123, 246, 241, 255, 227, 219, 171, 75,
|
||||||
|
/* 180 - 189 */ 150, 49, 98, 196, 149, 55, 110, 220, 165, 87,
|
||||||
|
/* 190 - 199 */ 174, 65, 130, 25, 50, 100, 200, 141, 7, 14,
|
||||||
|
/* 200 - 209 */ 28, 56, 112, 224, 221, 167, 83, 166, 81, 162,
|
||||||
|
/* 210 - 219 */ 89, 178, 121, 242, 249, 239, 195, 155, 43, 86,
|
||||||
|
/* 220 - 229 */ 172, 69, 138, 9, 18, 36, 72, 144, 61, 122,
|
||||||
|
/* 230 - 239 */ 244, 245, 247, 243, 251, 235, 203, 139, 11, 22,
|
||||||
|
/* 240 - 249 */ 44, 88, 176, 125, 250, 233, 207, 131, 27, 54,
|
||||||
|
/* 250 - 255 */ 108, 216, 173, 71, 142, 1}
|
||||||
|
|
||||||
|
gfLogTable = [256]int{
|
||||||
|
/* 0 - 9 */ -1, 0, 1, 25, 2, 50, 26, 198, 3, 223,
|
||||||
|
/* 10 - 19 */ 51, 238, 27, 104, 199, 75, 4, 100, 224, 14,
|
||||||
|
/* 20 - 29 */ 52, 141, 239, 129, 28, 193, 105, 248, 200, 8,
|
||||||
|
/* 30 - 39 */ 76, 113, 5, 138, 101, 47, 225, 36, 15, 33,
|
||||||
|
/* 40 - 49 */ 53, 147, 142, 218, 240, 18, 130, 69, 29, 181,
|
||||||
|
/* 50 - 59 */ 194, 125, 106, 39, 249, 185, 201, 154, 9, 120,
|
||||||
|
/* 60 - 69 */ 77, 228, 114, 166, 6, 191, 139, 98, 102, 221,
|
||||||
|
/* 70 - 79 */ 48, 253, 226, 152, 37, 179, 16, 145, 34, 136,
|
||||||
|
/* 80 - 89 */ 54, 208, 148, 206, 143, 150, 219, 189, 241, 210,
|
||||||
|
/* 90 - 99 */ 19, 92, 131, 56, 70, 64, 30, 66, 182, 163,
|
||||||
|
/* 100 - 109 */ 195, 72, 126, 110, 107, 58, 40, 84, 250, 133,
|
||||||
|
/* 110 - 119 */ 186, 61, 202, 94, 155, 159, 10, 21, 121, 43,
|
||||||
|
/* 120 - 129 */ 78, 212, 229, 172, 115, 243, 167, 87, 7, 112,
|
||||||
|
/* 130 - 139 */ 192, 247, 140, 128, 99, 13, 103, 74, 222, 237,
|
||||||
|
/* 140 - 149 */ 49, 197, 254, 24, 227, 165, 153, 119, 38, 184,
|
||||||
|
/* 150 - 159 */ 180, 124, 17, 68, 146, 217, 35, 32, 137, 46,
|
||||||
|
/* 160 - 169 */ 55, 63, 209, 91, 149, 188, 207, 205, 144, 135,
|
||||||
|
/* 170 - 179 */ 151, 178, 220, 252, 190, 97, 242, 86, 211, 171,
|
||||||
|
/* 180 - 189 */ 20, 42, 93, 158, 132, 60, 57, 83, 71, 109,
|
||||||
|
/* 190 - 199 */ 65, 162, 31, 45, 67, 216, 183, 123, 164, 118,
|
||||||
|
/* 200 - 209 */ 196, 23, 73, 236, 127, 12, 111, 246, 108, 161,
|
||||||
|
/* 210 - 219 */ 59, 82, 41, 157, 85, 170, 251, 96, 134, 177,
|
||||||
|
/* 220 - 229 */ 187, 204, 62, 90, 203, 89, 95, 176, 156, 169,
|
||||||
|
/* 230 - 239 */ 160, 81, 11, 245, 22, 235, 122, 117, 44, 215,
|
||||||
|
/* 240 - 249 */ 79, 174, 213, 233, 230, 231, 173, 232, 116, 214,
|
||||||
|
/* 250 - 255 */ 244, 234, 168, 80, 88, 175}
|
||||||
|
)
|
||||||
|
|
||||||
|
// gfElement is an element in GF(2^8).
|
||||||
|
type gfElement uint8
|
||||||
|
|
||||||
|
// newGFElement creates and returns a new gfElement.
|
||||||
|
func newGFElement(data byte) gfElement {
|
||||||
|
return gfElement(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfAdd returns a + b.
|
||||||
|
func gfAdd(a, b gfElement) gfElement {
|
||||||
|
return a ^ b
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfSub returns a - b.
|
||||||
|
//
|
||||||
|
// Note addition is equivalent to subtraction in GF(2).
|
||||||
|
func gfSub(a, b gfElement) gfElement {
|
||||||
|
return a ^ b
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfMultiply returns a * b.
|
||||||
|
func gfMultiply(a, b gfElement) gfElement {
|
||||||
|
if a == gfZero || b == gfZero {
|
||||||
|
return gfZero
|
||||||
|
}
|
||||||
|
|
||||||
|
return gfExpTable[(gfLogTable[a]+gfLogTable[b])%255]
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfDivide returns a / b.
|
||||||
|
//
|
||||||
|
// Divide by zero results in a panic.
|
||||||
|
func gfDivide(a, b gfElement) gfElement {
|
||||||
|
if a == gfZero {
|
||||||
|
return gfZero
|
||||||
|
} else if b == gfZero {
|
||||||
|
log.Panicln("Divide by zero")
|
||||||
|
}
|
||||||
|
|
||||||
|
return gfMultiply(a, gfInverse(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfInverse returns the multiplicative inverse of a, a^-1.
|
||||||
|
//
|
||||||
|
// a * a^-1 = 1
|
||||||
|
func gfInverse(a gfElement) gfElement {
|
||||||
|
if a == gfZero {
|
||||||
|
log.Panicln("No multiplicative inverse of 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return gfExpTable[255-gfLogTable[a]]
|
||||||
|
}
|
||||||
|
|
||||||
|
// a^i | bits | polynomial | decimal
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// 0 | 000000000 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 0
|
||||||
|
// a^0 | 000000001 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 1
|
||||||
|
// a^1 | 000000010 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 2
|
||||||
|
// a^2 | 000000100 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 4
|
||||||
|
// a^3 | 000001000 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 8
|
||||||
|
// a^4 | 000010000 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 16
|
||||||
|
// a^5 | 000100000 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 32
|
||||||
|
// a^6 | 001000000 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 64
|
||||||
|
// a^7 | 010000000 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 128
|
||||||
|
// a^8 | 000011101 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 29
|
||||||
|
// a^9 | 000111010 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 58
|
||||||
|
// a^10 | 001110100 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 116
|
||||||
|
// a^11 | 011101000 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 232
|
||||||
|
// a^12 | 011001101 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 205
|
||||||
|
// a^13 | 010000111 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 135
|
||||||
|
// a^14 | 000010011 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 19
|
||||||
|
// a^15 | 000100110 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 38
|
||||||
|
// a^16 | 001001100 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 76
|
||||||
|
// a^17 | 010011000 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 152
|
||||||
|
// a^18 | 000101101 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 45
|
||||||
|
// a^19 | 001011010 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 90
|
||||||
|
// a^20 | 010110100 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 180
|
||||||
|
// a^21 | 001110101 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 117
|
||||||
|
// a^22 | 011101010 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 234
|
||||||
|
// a^23 | 011001001 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 201
|
||||||
|
// a^24 | 010001111 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 143
|
||||||
|
// a^25 | 000000011 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 3
|
||||||
|
// a^26 | 000000110 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 6
|
||||||
|
// a^27 | 000001100 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 12
|
||||||
|
// a^28 | 000011000 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 24
|
||||||
|
// a^29 | 000110000 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 48
|
||||||
|
// a^30 | 001100000 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 96
|
||||||
|
// a^31 | 011000000 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 192
|
||||||
|
// a^32 | 010011101 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 157
|
||||||
|
// a^33 | 000100111 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 39
|
||||||
|
// a^34 | 001001110 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 78
|
||||||
|
// a^35 | 010011100 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 156
|
||||||
|
// a^36 | 000100101 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 37
|
||||||
|
// a^37 | 001001010 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 74
|
||||||
|
// a^38 | 010010100 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 148
|
||||||
|
// a^39 | 000110101 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 53
|
||||||
|
// a^40 | 001101010 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 106
|
||||||
|
// a^41 | 011010100 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 212
|
||||||
|
// a^42 | 010110101 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 181
|
||||||
|
// a^43 | 001110111 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 119
|
||||||
|
// a^44 | 011101110 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 238
|
||||||
|
// a^45 | 011000001 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 193
|
||||||
|
// a^46 | 010011111 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 159
|
||||||
|
// a^47 | 000100011 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 35
|
||||||
|
// a^48 | 001000110 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 70
|
||||||
|
// a^49 | 010001100 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 140
|
||||||
|
// a^50 | 000000101 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 5
|
||||||
|
// a^51 | 000001010 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 10
|
||||||
|
// a^52 | 000010100 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 20
|
||||||
|
// a^53 | 000101000 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 40
|
||||||
|
// a^54 | 001010000 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 80
|
||||||
|
// a^55 | 010100000 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 160
|
||||||
|
// a^56 | 001011101 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 93
|
||||||
|
// a^57 | 010111010 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 186
|
||||||
|
// a^58 | 001101001 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 105
|
||||||
|
// a^59 | 011010010 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 210
|
||||||
|
// a^60 | 010111001 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 185
|
||||||
|
// a^61 | 001101111 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 111
|
||||||
|
// a^62 | 011011110 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 222
|
||||||
|
// a^63 | 010100001 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 161
|
||||||
|
// a^64 | 001011111 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 95
|
||||||
|
// a^65 | 010111110 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 190
|
||||||
|
// a^66 | 001100001 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 97
|
||||||
|
// a^67 | 011000010 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 194
|
||||||
|
// a^68 | 010011001 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 153
|
||||||
|
// a^69 | 000101111 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 47
|
||||||
|
// a^70 | 001011110 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 94
|
||||||
|
// a^71 | 010111100 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 188
|
||||||
|
// a^72 | 001100101 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 101
|
||||||
|
// a^73 | 011001010 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 202
|
||||||
|
// a^74 | 010001001 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 137
|
||||||
|
// a^75 | 000001111 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 15
|
||||||
|
// a^76 | 000011110 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 30
|
||||||
|
// a^77 | 000111100 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 60
|
||||||
|
// a^78 | 001111000 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 120
|
||||||
|
// a^79 | 011110000 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 240
|
||||||
|
// a^80 | 011111101 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 253
|
||||||
|
// a^81 | 011100111 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 231
|
||||||
|
// a^82 | 011010011 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 211
|
||||||
|
// a^83 | 010111011 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 187
|
||||||
|
// a^84 | 001101011 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 107
|
||||||
|
// a^85 | 011010110 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 214
|
||||||
|
// a^86 | 010110001 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 177
|
||||||
|
// a^87 | 001111111 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 127
|
||||||
|
// a^88 | 011111110 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 254
|
||||||
|
// a^89 | 011100001 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 225
|
||||||
|
// a^90 | 011011111 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 223
|
||||||
|
// a^91 | 010100011 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 163
|
||||||
|
// a^92 | 001011011 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 91
|
||||||
|
// a^93 | 010110110 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 182
|
||||||
|
// a^94 | 001110001 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 113
|
||||||
|
// a^95 | 011100010 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 226
|
||||||
|
// a^96 | 011011001 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 217
|
||||||
|
// a^97 | 010101111 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 175
|
||||||
|
// a^98 | 001000011 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 67
|
||||||
|
// a^99 | 010000110 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 134
|
||||||
|
// a^100 | 000010001 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 17
|
||||||
|
// a^101 | 000100010 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 34
|
||||||
|
// a^102 | 001000100 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 68
|
||||||
|
// a^103 | 010001000 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 136
|
||||||
|
// a^104 | 000001101 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 13
|
||||||
|
// a^105 | 000011010 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 26
|
||||||
|
// a^106 | 000110100 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 52
|
||||||
|
// a^107 | 001101000 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 104
|
||||||
|
// a^108 | 011010000 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 208
|
||||||
|
// a^109 | 010111101 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 189
|
||||||
|
// a^110 | 001100111 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 103
|
||||||
|
// a^111 | 011001110 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 206
|
||||||
|
// a^112 | 010000001 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 129
|
||||||
|
// a^113 | 000011111 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 31
|
||||||
|
// a^114 | 000111110 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 62
|
||||||
|
// a^115 | 001111100 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 124
|
||||||
|
// a^116 | 011111000 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 248
|
||||||
|
// a^117 | 011101101 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 237
|
||||||
|
// a^118 | 011000111 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 199
|
||||||
|
// a^119 | 010010011 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 147
|
||||||
|
// a^120 | 000111011 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 59
|
||||||
|
// a^121 | 001110110 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 118
|
||||||
|
// a^122 | 011101100 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 236
|
||||||
|
// a^123 | 011000101 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 197
|
||||||
|
// a^124 | 010010111 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 151
|
||||||
|
// a^125 | 000110011 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 51
|
||||||
|
// a^126 | 001100110 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 102
|
||||||
|
// a^127 | 011001100 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 204
|
||||||
|
// a^128 | 010000101 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 133
|
||||||
|
// a^129 | 000010111 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 23
|
||||||
|
// a^130 | 000101110 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 46
|
||||||
|
// a^131 | 001011100 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 92
|
||||||
|
// a^132 | 010111000 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 184
|
||||||
|
// a^133 | 001101101 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 109
|
||||||
|
// a^134 | 011011010 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 218
|
||||||
|
// a^135 | 010101001 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 169
|
||||||
|
// a^136 | 001001111 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 79
|
||||||
|
// a^137 | 010011110 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 158
|
||||||
|
// a^138 | 000100001 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 33
|
||||||
|
// a^139 | 001000010 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 66
|
||||||
|
// a^140 | 010000100 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 132
|
||||||
|
// a^141 | 000010101 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 21
|
||||||
|
// a^142 | 000101010 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 42
|
||||||
|
// a^143 | 001010100 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 84
|
||||||
|
// a^144 | 010101000 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 168
|
||||||
|
// a^145 | 001001101 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 77
|
||||||
|
// a^146 | 010011010 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 154
|
||||||
|
// a^147 | 000101001 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 41
|
||||||
|
// a^148 | 001010010 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 82
|
||||||
|
// a^149 | 010100100 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 164
|
||||||
|
// a^150 | 001010101 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 85
|
||||||
|
// a^151 | 010101010 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 170
|
||||||
|
// a^152 | 001001001 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 73
|
||||||
|
// a^153 | 010010010 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 146
|
||||||
|
// a^154 | 000111001 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 57
|
||||||
|
// a^155 | 001110010 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 114
|
||||||
|
// a^156 | 011100100 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 228
|
||||||
|
// a^157 | 011010101 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 213
|
||||||
|
// a^158 | 010110111 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 183
|
||||||
|
// a^159 | 001110011 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 115
|
||||||
|
// a^160 | 011100110 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 230
|
||||||
|
// a^161 | 011010001 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 209
|
||||||
|
// a^162 | 010111111 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 191
|
||||||
|
// a^163 | 001100011 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 99
|
||||||
|
// a^164 | 011000110 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 198
|
||||||
|
// a^165 | 010010001 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 145
|
||||||
|
// a^166 | 000111111 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 63
|
||||||
|
// a^167 | 001111110 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 126
|
||||||
|
// a^168 | 011111100 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 252
|
||||||
|
// a^169 | 011100101 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 229
|
||||||
|
// a^170 | 011010111 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 215
|
||||||
|
// a^171 | 010110011 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 179
|
||||||
|
// a^172 | 001111011 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 123
|
||||||
|
// a^173 | 011110110 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 246
|
||||||
|
// a^174 | 011110001 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 241
|
||||||
|
// a^175 | 011111111 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 255
|
||||||
|
// a^176 | 011100011 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 227
|
||||||
|
// a^177 | 011011011 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 219
|
||||||
|
// a^178 | 010101011 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 171
|
||||||
|
// a^179 | 001001011 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 75
|
||||||
|
// a^180 | 010010110 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 150
|
||||||
|
// a^181 | 000110001 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 49
|
||||||
|
// a^182 | 001100010 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 98
|
||||||
|
// a^183 | 011000100 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 196
|
||||||
|
// a^184 | 010010101 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 149
|
||||||
|
// a^185 | 000110111 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 55
|
||||||
|
// a^186 | 001101110 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 110
|
||||||
|
// a^187 | 011011100 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 220
|
||||||
|
// a^188 | 010100101 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 165
|
||||||
|
// a^189 | 001010111 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 87
|
||||||
|
// a^190 | 010101110 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 174
|
||||||
|
// a^191 | 001000001 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 65
|
||||||
|
// a^192 | 010000010 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 130
|
||||||
|
// a^193 | 000011001 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 25
|
||||||
|
// a^194 | 000110010 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 50
|
||||||
|
// a^195 | 001100100 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 100
|
||||||
|
// a^196 | 011001000 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 200
|
||||||
|
// a^197 | 010001101 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 141
|
||||||
|
// a^198 | 000000111 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 7
|
||||||
|
// a^199 | 000001110 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 14
|
||||||
|
// a^200 | 000011100 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 28
|
||||||
|
// a^201 | 000111000 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 56
|
||||||
|
// a^202 | 001110000 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 112
|
||||||
|
// a^203 | 011100000 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 224
|
||||||
|
// a^204 | 011011101 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 221
|
||||||
|
// a^205 | 010100111 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 167
|
||||||
|
// a^206 | 001010011 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 83
|
||||||
|
// a^207 | 010100110 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 166
|
||||||
|
// a^208 | 001010001 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 81
|
||||||
|
// a^209 | 010100010 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 162
|
||||||
|
// a^210 | 001011001 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 89
|
||||||
|
// a^211 | 010110010 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 178
|
||||||
|
// a^212 | 001111001 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 121
|
||||||
|
// a^213 | 011110010 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 242
|
||||||
|
// a^214 | 011111001 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 249
|
||||||
|
// a^215 | 011101111 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 239
|
||||||
|
// a^216 | 011000011 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 195
|
||||||
|
// a^217 | 010011011 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 155
|
||||||
|
// a^218 | 000101011 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 43
|
||||||
|
// a^219 | 001010110 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 86
|
||||||
|
// a^220 | 010101100 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 172
|
||||||
|
// a^221 | 001000101 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 69
|
||||||
|
// a^222 | 010001010 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 138
|
||||||
|
// a^223 | 000001001 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 9
|
||||||
|
// a^224 | 000010010 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 18
|
||||||
|
// a^225 | 000100100 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 36
|
||||||
|
// a^226 | 001001000 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 72
|
||||||
|
// a^227 | 010010000 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 144
|
||||||
|
// a^228 | 000111101 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 61
|
||||||
|
// a^229 | 001111010 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 122
|
||||||
|
// a^230 | 011110100 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 244
|
||||||
|
// a^231 | 011110101 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 245
|
||||||
|
// a^232 | 011110111 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 247
|
||||||
|
// a^233 | 011110011 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 243
|
||||||
|
// a^234 | 011111011 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 251
|
||||||
|
// a^235 | 011101011 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 235
|
||||||
|
// a^236 | 011001011 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 203
|
||||||
|
// a^237 | 010001011 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 139
|
||||||
|
// a^238 | 000001011 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 11
|
||||||
|
// a^239 | 000010110 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 22
|
||||||
|
// a^240 | 000101100 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 44
|
||||||
|
// a^241 | 001011000 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 88
|
||||||
|
// a^242 | 010110000 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 176
|
||||||
|
// a^243 | 001111101 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 125
|
||||||
|
// a^244 | 011111010 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 250
|
||||||
|
// a^245 | 011101001 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 233
|
||||||
|
// a^246 | 011001111 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 207
|
||||||
|
// a^247 | 010000011 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 131
|
||||||
|
// a^248 | 000011011 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 27
|
||||||
|
// a^249 | 000110110 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 54
|
||||||
|
// a^250 | 001101100 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 108
|
||||||
|
// a^251 | 011011000 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 216
|
||||||
|
// a^252 | 010101101 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 173
|
||||||
|
// a^253 | 001000111 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 71
|
||||||
|
// a^254 | 010001110 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 142
|
||||||
|
// a^255 | 000000001 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 1
|
83
vendor/github.com/skip2/go-qrcode/reedsolomon/gf2_8_test.go
generated
vendored
Normal file
83
vendor/github.com/skip2/go-qrcode/reedsolomon/gf2_8_test.go
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package reedsolomon
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestGFMultiplicationIdentities(t *testing.T) {
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
value := gfElement(i)
|
||||||
|
if gfMultiply(gfZero, value) != gfZero {
|
||||||
|
t.Errorf("0 . %d != 0", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gfMultiply(value, gfOne) != value {
|
||||||
|
t.Errorf("%d . 1 == %d, want %d", value, gfMultiply(value, gfOne), value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGFMultiplicationAndDivision(t *testing.T) {
|
||||||
|
// a * b == result
|
||||||
|
var tests = []struct {
|
||||||
|
a gfElement
|
||||||
|
b gfElement
|
||||||
|
result gfElement
|
||||||
|
}{
|
||||||
|
{0, 29, 0},
|
||||||
|
{1, 1, 1},
|
||||||
|
{1, 32, 32},
|
||||||
|
{2, 4, 8},
|
||||||
|
{16, 128, 232},
|
||||||
|
{17, 17, 28},
|
||||||
|
{27, 9, 195},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
result := gfMultiply(test.a, test.b)
|
||||||
|
|
||||||
|
if result != test.result {
|
||||||
|
t.Errorf("%d * %d = %d, want %d", test.a, test.b, result, test.result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if test.b != gfZero && test.result != gfZero {
|
||||||
|
b := gfDivide(test.result, test.a)
|
||||||
|
|
||||||
|
if b != test.b {
|
||||||
|
t.Errorf("%d / %d = %d, want %d", test.result, test.a, b, test.b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGFInverse(t *testing.T) {
|
||||||
|
for i := 1; i < 256; i++ {
|
||||||
|
a := gfElement(i)
|
||||||
|
inverse := gfInverse(a)
|
||||||
|
|
||||||
|
result := gfMultiply(a, inverse)
|
||||||
|
|
||||||
|
if result != gfOne {
|
||||||
|
t.Errorf("%d * %d^-1 == %d, want %d", a, inverse, result, gfOne)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGFDivide(t *testing.T) {
|
||||||
|
for i := 1; i < 256; i++ {
|
||||||
|
for j := 1; j < 256; j++ {
|
||||||
|
// a * b == product
|
||||||
|
a := gfElement(i)
|
||||||
|
b := gfElement(j)
|
||||||
|
product := gfMultiply(a, b)
|
||||||
|
|
||||||
|
// product / b == a
|
||||||
|
result := gfDivide(product, b)
|
||||||
|
|
||||||
|
if result != a {
|
||||||
|
t.Errorf("%d / %d == %d, want %d", product, b, result, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
216
vendor/github.com/skip2/go-qrcode/reedsolomon/gf_poly.go
generated
vendored
Normal file
216
vendor/github.com/skip2/go-qrcode/reedsolomon/gf_poly.go
generated
vendored
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package reedsolomon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||||||
|
)
|
||||||
|
|
||||||
|
// gfPoly is a polynomial over GF(2^8).
|
||||||
|
type gfPoly struct {
|
||||||
|
// The ith value is the coefficient of the ith degree of x.
|
||||||
|
// term[0]*(x^0) + term[1]*(x^1) + term[2]*(x^2) ...
|
||||||
|
term []gfElement
|
||||||
|
}
|
||||||
|
|
||||||
|
// newGFPolyFromData returns |data| as a polynomial over GF(2^8).
|
||||||
|
//
|
||||||
|
// Each data byte becomes the coefficient of an x term.
|
||||||
|
//
|
||||||
|
// For an n byte input the polynomial is:
|
||||||
|
// data[n-1]*(x^n-1) + data[n-2]*(x^n-2) ... + data[0]*(x^0).
|
||||||
|
func newGFPolyFromData(data *bitset.Bitset) gfPoly {
|
||||||
|
numTotalBytes := data.Len() / 8
|
||||||
|
if data.Len()%8 != 0 {
|
||||||
|
numTotalBytes++
|
||||||
|
}
|
||||||
|
|
||||||
|
result := gfPoly{term: make([]gfElement, numTotalBytes)}
|
||||||
|
|
||||||
|
i := numTotalBytes - 1
|
||||||
|
for j := 0; j < data.Len(); j += 8 {
|
||||||
|
result.term[i] = gfElement(data.ByteAt(j))
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// newGFPolyMonomial returns term*(x^degree).
|
||||||
|
func newGFPolyMonomial(term gfElement, degree int) gfPoly {
|
||||||
|
if term == gfZero {
|
||||||
|
return gfPoly{}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := gfPoly{term: make([]gfElement, degree+1)}
|
||||||
|
result.term[degree] = term
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e gfPoly) data(numTerms int) []byte {
|
||||||
|
result := make([]byte, numTerms)
|
||||||
|
|
||||||
|
i := numTerms - len(e.term)
|
||||||
|
for j := len(e.term) - 1; j >= 0; j-- {
|
||||||
|
result[i] = byte(e.term[j])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// numTerms returns the number of
|
||||||
|
func (e gfPoly) numTerms() int {
|
||||||
|
return len(e.term)
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfPolyMultiply returns a * b.
|
||||||
|
func gfPolyMultiply(a, b gfPoly) gfPoly {
|
||||||
|
numATerms := a.numTerms()
|
||||||
|
numBTerms := b.numTerms()
|
||||||
|
|
||||||
|
result := gfPoly{term: make([]gfElement, numATerms+numBTerms)}
|
||||||
|
|
||||||
|
for i := 0; i < numATerms; i++ {
|
||||||
|
for j := 0; j < numBTerms; j++ {
|
||||||
|
if a.term[i] != 0 && b.term[j] != 0 {
|
||||||
|
monomial := gfPoly{term: make([]gfElement, i+j+1)}
|
||||||
|
monomial.term[i+j] = gfMultiply(a.term[i], b.term[j])
|
||||||
|
|
||||||
|
result = gfPolyAdd(result, monomial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.normalised()
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfPolyRemainder return the remainder of numerator / denominator.
|
||||||
|
func gfPolyRemainder(numerator, denominator gfPoly) gfPoly {
|
||||||
|
if denominator.equals(gfPoly{}) {
|
||||||
|
log.Panicln("Remainder by zero")
|
||||||
|
}
|
||||||
|
|
||||||
|
remainder := numerator
|
||||||
|
|
||||||
|
for remainder.numTerms() >= denominator.numTerms() {
|
||||||
|
degree := remainder.numTerms() - denominator.numTerms()
|
||||||
|
coefficient := gfDivide(remainder.term[remainder.numTerms()-1],
|
||||||
|
denominator.term[denominator.numTerms()-1])
|
||||||
|
|
||||||
|
divisor := gfPolyMultiply(denominator,
|
||||||
|
newGFPolyMonomial(coefficient, degree))
|
||||||
|
|
||||||
|
remainder = gfPolyAdd(remainder, divisor)
|
||||||
|
}
|
||||||
|
|
||||||
|
return remainder.normalised()
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfPolyAdd returns a + b.
|
||||||
|
func gfPolyAdd(a, b gfPoly) gfPoly {
|
||||||
|
numATerms := a.numTerms()
|
||||||
|
numBTerms := b.numTerms()
|
||||||
|
|
||||||
|
numTerms := numATerms
|
||||||
|
if numBTerms > numTerms {
|
||||||
|
numTerms = numBTerms
|
||||||
|
}
|
||||||
|
|
||||||
|
result := gfPoly{term: make([]gfElement, numTerms)}
|
||||||
|
|
||||||
|
for i := 0; i < numTerms; i++ {
|
||||||
|
switch {
|
||||||
|
case numATerms > i && numBTerms > i:
|
||||||
|
result.term[i] = gfAdd(a.term[i], b.term[i])
|
||||||
|
case numATerms > i:
|
||||||
|
result.term[i] = a.term[i]
|
||||||
|
default:
|
||||||
|
result.term[i] = b.term[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.normalised()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e gfPoly) normalised() gfPoly {
|
||||||
|
numTerms := e.numTerms()
|
||||||
|
maxNonzeroTerm := numTerms - 1
|
||||||
|
|
||||||
|
for i := numTerms - 1; i >= 0; i-- {
|
||||||
|
if e.term[i] != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
maxNonzeroTerm = i - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxNonzeroTerm < 0 {
|
||||||
|
return gfPoly{}
|
||||||
|
} else if maxNonzeroTerm < numTerms-1 {
|
||||||
|
e.term = e.term[0 : maxNonzeroTerm+1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e gfPoly) string(useIndexForm bool) string {
|
||||||
|
var str string
|
||||||
|
numTerms := e.numTerms()
|
||||||
|
|
||||||
|
for i := numTerms - 1; i >= 0; i-- {
|
||||||
|
if e.term[i] > 0 {
|
||||||
|
if len(str) > 0 {
|
||||||
|
str += " + "
|
||||||
|
}
|
||||||
|
|
||||||
|
if !useIndexForm {
|
||||||
|
str += fmt.Sprintf("%dx^%d", e.term[i], i)
|
||||||
|
} else {
|
||||||
|
str += fmt.Sprintf("a^%dx^%d", gfLogTable[e.term[i]], i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(str) == 0 {
|
||||||
|
str = "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// equals returns true if e == other.
|
||||||
|
func (e gfPoly) equals(other gfPoly) bool {
|
||||||
|
var minecPoly *gfPoly
|
||||||
|
var maxecPoly *gfPoly
|
||||||
|
|
||||||
|
if e.numTerms() > other.numTerms() {
|
||||||
|
minecPoly = &other
|
||||||
|
maxecPoly = &e
|
||||||
|
} else {
|
||||||
|
minecPoly = &e
|
||||||
|
maxecPoly = &other
|
||||||
|
}
|
||||||
|
|
||||||
|
numMinTerms := minecPoly.numTerms()
|
||||||
|
numMaxTerms := maxecPoly.numTerms()
|
||||||
|
|
||||||
|
for i := 0; i < numMinTerms; i++ {
|
||||||
|
if e.term[i] != other.term[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := numMinTerms; i < numMaxTerms; i++ {
|
||||||
|
if maxecPoly.term[i] != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
182
vendor/github.com/skip2/go-qrcode/reedsolomon/gf_poly_test.go
generated
vendored
Normal file
182
vendor/github.com/skip2/go-qrcode/reedsolomon/gf_poly_test.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package reedsolomon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGFPolyAdd(t *testing.T) {
|
||||||
|
// a + b == result
|
||||||
|
var tests = []struct {
|
||||||
|
a gfPoly
|
||||||
|
b gfPoly
|
||||||
|
result gfPoly
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{0, 0, 0}},
|
||||||
|
gfPoly{[]gfElement{0}},
|
||||||
|
gfPoly{[]gfElement{}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{1, 0}},
|
||||||
|
gfPoly{[]gfElement{1, 0}},
|
||||||
|
gfPoly{[]gfElement{0, 0}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{0xA0, 0x80, 0xFF, 0x00}},
|
||||||
|
gfPoly{[]gfElement{0x0A, 0x82}},
|
||||||
|
gfPoly{[]gfElement{0xAA, 0x02, 0xFF}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
result := gfPolyAdd(test.a, test.b)
|
||||||
|
|
||||||
|
if !test.result.equals(result) {
|
||||||
|
t.Errorf("%s * %s != %s (got %s)\n", test.a.string(false), test.b.string(false),
|
||||||
|
test.result.string(false), result.string(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(result.term) > 0 && result.term[len(result.term)-1] == 0 {
|
||||||
|
t.Errorf("Result's maximum term coefficient is zero")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGFPolyequals(t *testing.T) {
|
||||||
|
// a == b if isEqual
|
||||||
|
var tests = []struct {
|
||||||
|
a gfPoly
|
||||||
|
b gfPoly
|
||||||
|
isEqual bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{0}},
|
||||||
|
gfPoly{[]gfElement{0}},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{1}},
|
||||||
|
gfPoly{[]gfElement{0}},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{1, 0, 1, 0, 1}},
|
||||||
|
gfPoly{[]gfElement{1, 0, 1, 0, 1}},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{1, 0, 1}},
|
||||||
|
gfPoly{[]gfElement{1, 0, 1, 0, 0}},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
isEqual := test.a.equals(test.b)
|
||||||
|
|
||||||
|
if isEqual != test.isEqual {
|
||||||
|
t.Errorf("%s and %s equality is %t (got %t)\n", test.a.string(false), test.b.string(false),
|
||||||
|
test.isEqual, isEqual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGFPolyMultiply(t *testing.T) {
|
||||||
|
// a * b == result
|
||||||
|
var tests = []struct {
|
||||||
|
a gfPoly
|
||||||
|
b gfPoly
|
||||||
|
result gfPoly
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{0, 0, 1}},
|
||||||
|
gfPoly{[]gfElement{9}},
|
||||||
|
gfPoly{[]gfElement{0, 0, 9}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{0, 16, 1}},
|
||||||
|
gfPoly{[]gfElement{128, 2}},
|
||||||
|
gfPoly{[]gfElement{0, 232, 160, 2}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{254, 120, 88, 44, 11, 1}},
|
||||||
|
gfPoly{[]gfElement{16, 2, 0, 51, 44}},
|
||||||
|
gfPoly{[]gfElement{91, 50, 25, 184, 194, 105, 45, 244, 58, 44}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
result := gfPolyMultiply(test.a, test.b)
|
||||||
|
|
||||||
|
if !test.result.equals(result) {
|
||||||
|
t.Errorf("%s * %s = %s (got %s)\n",
|
||||||
|
test.a.string(false),
|
||||||
|
test.b.string(false),
|
||||||
|
test.result.string(false),
|
||||||
|
result.string(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGFPolyRemainder(t *testing.T) {
|
||||||
|
// numerator / denominator == quotient + remainder.
|
||||||
|
var tests = []struct {
|
||||||
|
numerator gfPoly
|
||||||
|
denominator gfPoly
|
||||||
|
remainder gfPoly
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{1}},
|
||||||
|
gfPoly{[]gfElement{1}},
|
||||||
|
gfPoly{[]gfElement{0}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{1, 0}},
|
||||||
|
gfPoly{[]gfElement{1}},
|
||||||
|
gfPoly{[]gfElement{0}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{1}},
|
||||||
|
gfPoly{[]gfElement{1, 0}},
|
||||||
|
gfPoly{[]gfElement{1}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{1, 0, 1}},
|
||||||
|
gfPoly{[]gfElement{0, 1}},
|
||||||
|
gfPoly{[]gfElement{1}},
|
||||||
|
},
|
||||||
|
// (x^12 + x^10) / (x^10 + x^8 + x^5 + x^4 + x^2 + x^1 + x^0) =
|
||||||
|
// (x^10 + x^8 + x^5 + x^4 + x^2 + x^1 + x^0) * x^2 +
|
||||||
|
// (x^7 + x^6 + x^4 + x^3 + x^2) (the remainder)
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}},
|
||||||
|
gfPoly{[]gfElement{1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1}},
|
||||||
|
gfPoly{[]gfElement{0, 0, 1, 1, 1, 0, 1, 1}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{91, 50, 25, 184, 194, 105, 45, 244, 58, 44}},
|
||||||
|
gfPoly{[]gfElement{254, 120, 88, 44, 11, 1}},
|
||||||
|
gfPoly{[]gfElement{}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gfPoly{[]gfElement{0, 0, 0, 0, 0, 0, 195, 172, 24, 64}},
|
||||||
|
gfPoly{[]gfElement{116, 147, 63, 198, 31, 1}},
|
||||||
|
gfPoly{[]gfElement{48, 174, 34, 13, 134}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
remainder := gfPolyRemainder(test.numerator, test.denominator)
|
||||||
|
|
||||||
|
if !test.remainder.equals(remainder) {
|
||||||
|
t.Errorf("%s / %s, remainder = %s (got %s)\n",
|
||||||
|
test.numerator.string(false),
|
||||||
|
test.denominator.string(false),
|
||||||
|
test.remainder.string(false),
|
||||||
|
remainder.string(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
vendor/github.com/skip2/go-qrcode/reedsolomon/reed_solomon.go
generated
vendored
Normal file
73
vendor/github.com/skip2/go-qrcode/reedsolomon/reed_solomon.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
// Package reedsolomon provides error correction encoding for QR Code 2005.
|
||||||
|
//
|
||||||
|
// QR Code 2005 uses a Reed-Solomon error correcting code to detect and correct
|
||||||
|
// errors encountered during decoding.
|
||||||
|
//
|
||||||
|
// The generated RS codes are systematic, and consist of the input data with
|
||||||
|
// error correction bytes appended.
|
||||||
|
package reedsolomon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Encode data for QR Code 2005 using the appropriate Reed-Solomon code.
|
||||||
|
//
|
||||||
|
// numECBytes is the number of error correction bytes to append, and is
|
||||||
|
// determined by the target QR Code's version and error correction level.
|
||||||
|
//
|
||||||
|
// ISO/IEC 18004 table 9 specifies the numECBytes required. e.g. a 1-L code has
|
||||||
|
// numECBytes=7.
|
||||||
|
func Encode(data *bitset.Bitset, numECBytes int) *bitset.Bitset {
|
||||||
|
// Create a polynomial representing |data|.
|
||||||
|
//
|
||||||
|
// The bytes are interpreted as the sequence of coefficients of a polynomial.
|
||||||
|
// The last byte's value becomes the x^0 coefficient, the second to last
|
||||||
|
// becomes the x^1 coefficient and so on.
|
||||||
|
ecpoly := newGFPolyFromData(data)
|
||||||
|
ecpoly = gfPolyMultiply(ecpoly, newGFPolyMonomial(gfOne, numECBytes))
|
||||||
|
|
||||||
|
// Pick the generator polynomial.
|
||||||
|
generator := rsGeneratorPoly(numECBytes)
|
||||||
|
|
||||||
|
// Generate the error correction bytes.
|
||||||
|
remainder := gfPolyRemainder(ecpoly, generator)
|
||||||
|
|
||||||
|
// Combine the data & error correcting bytes.
|
||||||
|
// The mathematically correct answer is:
|
||||||
|
//
|
||||||
|
// result := gfPolyAdd(ecpoly, remainder).
|
||||||
|
//
|
||||||
|
// The encoding used by QR Code 2005 is slightly different this result: To
|
||||||
|
// preserve the original |data| bit sequence exactly, the data and remainder
|
||||||
|
// are combined manually below. This ensures any most significant zero bits
|
||||||
|
// are preserved (and not optimised away).
|
||||||
|
result := bitset.Clone(data)
|
||||||
|
result.AppendBytes(remainder.data(numECBytes))
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// rsGeneratorPoly returns the Reed-Solomon generator polynomial with |degree|.
|
||||||
|
//
|
||||||
|
// The generator polynomial is calculated as:
|
||||||
|
// (x + a^0)(x + a^1)...(x + a^degree-1)
|
||||||
|
func rsGeneratorPoly(degree int) gfPoly {
|
||||||
|
if degree < 2 {
|
||||||
|
log.Panic("degree < 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
generator := gfPoly{term: []gfElement{1}}
|
||||||
|
|
||||||
|
for i := 0; i < degree; i++ {
|
||||||
|
nextPoly := gfPoly{term: []gfElement{gfExpTable[i], 1}}
|
||||||
|
generator = gfPolyMultiply(generator, nextPoly)
|
||||||
|
}
|
||||||
|
|
||||||
|
return generator
|
||||||
|
}
|
89
vendor/github.com/skip2/go-qrcode/reedsolomon/reed_solomon_test.go
generated
vendored
Normal file
89
vendor/github.com/skip2/go-qrcode/reedsolomon/reed_solomon_test.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package reedsolomon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGeneratorPoly(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
degree int
|
||||||
|
generator gfPoly
|
||||||
|
}{
|
||||||
|
// x^2 + 3x^1 + 2x^0 (the shortest generator poly)
|
||||||
|
{
|
||||||
|
2,
|
||||||
|
gfPoly{term: []gfElement{2, 3, 1}},
|
||||||
|
},
|
||||||
|
// x^5 + 31x^4 + 198x^3 + 63x^2 + 147x^1 + 116x^0
|
||||||
|
{
|
||||||
|
5,
|
||||||
|
gfPoly{term: []gfElement{116, 147, 63, 198, 31, 1}},
|
||||||
|
},
|
||||||
|
// x^68 + 131x^67 + 115x^66 + 9x^65 + 39x^64 + 18x^63 + 182x^62 + 60x^61 +
|
||||||
|
// 94x^60 + 223x^59 + 230x^58 + 157x^57 + 142x^56 + 119x^55 + 85x^54 +
|
||||||
|
// 107x^53 + 34x^52 + 174x^51 + 167x^50 + 109x^49 + 20x^48 + 185x^47 +
|
||||||
|
// 112x^46 + 145x^45 + 172x^44 + 224x^43 + 170x^42 + 182x^41 + 107x^40 +
|
||||||
|
// 38x^39 + 107x^38 + 71x^37 + 246x^36 + 230x^35 + 225x^34 + 144x^33 +
|
||||||
|
// 20x^32 + 14x^31 + 175x^30 + 226x^29 + 245x^28 + 20x^27 + 219x^26 +
|
||||||
|
// 212x^25 + 51x^24 + 158x^23 + 88x^22 + 63x^21 + 36x^20 + 199x^19 + 4x^18 +
|
||||||
|
// 80x^17 + 157x^16 + 211x^15 + 239x^14 + 255x^13 + 7x^12 + 119x^11 + 11x^10
|
||||||
|
// + 235x^9 + 12x^8 + 34x^7 + 149x^6 + 204x^5 + 8x^4 + 32x^3 + 29x^2 + 99x^1
|
||||||
|
// + 11x^0 (the longest generator poly)
|
||||||
|
{
|
||||||
|
68,
|
||||||
|
gfPoly{term: []gfElement{11, 99, 29, 32, 8, 204, 149, 34, 12,
|
||||||
|
235, 11, 119, 7, 255, 239, 211, 157, 80, 4, 199, 36, 63, 88, 158, 51, 212,
|
||||||
|
219, 20, 245, 226, 175, 14, 20, 144, 225, 230, 246, 71, 107, 38, 107, 182,
|
||||||
|
170, 224, 172, 145, 112, 185, 20, 109, 167, 174, 34, 107, 85, 119, 142,
|
||||||
|
157, 230, 223, 94, 60, 182, 18, 39, 9, 115, 131, 1}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
generator := rsGeneratorPoly(test.degree)
|
||||||
|
|
||||||
|
if !generator.equals(test.generator) {
|
||||||
|
t.Errorf("degree=%d generator=%s, want %s", test.degree,
|
||||||
|
generator.string(true), test.generator.string(true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncode(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
numECBytes int
|
||||||
|
data string
|
||||||
|
rsCode string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
5,
|
||||||
|
"01000000 00011000 10101100 11000011 00000000",
|
||||||
|
"01000000 00011000 10101100 11000011 00000000 10000110 00001101 00100010 10101110 00110000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
10,
|
||||||
|
"00010000 00100000 00001100 01010110 01100001 10000000 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001",
|
||||||
|
"00010000 00100000 00001100 01010110 01100001 10000000 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 10100101 00100100 11010100 11000001 11101101 00110110 11000111 10000111 00101100 01010101",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
data := bitset.NewFromBase2String(test.data)
|
||||||
|
rsCode := bitset.NewFromBase2String(test.rsCode)
|
||||||
|
|
||||||
|
result := Encode(data, test.numECBytes)
|
||||||
|
|
||||||
|
if !rsCode.Equals(result) {
|
||||||
|
t.Errorf("data=%s, numECBytes=%d, encoded=%s, want %s",
|
||||||
|
data.String(),
|
||||||
|
test.numECBytes,
|
||||||
|
result.String(),
|
||||||
|
rsCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
309
vendor/github.com/skip2/go-qrcode/regular_symbol.go
generated
vendored
Normal file
309
vendor/github.com/skip2/go-qrcode/regular_symbol.go
generated
vendored
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||||||
|
)
|
||||||
|
|
||||||
|
type regularSymbol struct {
|
||||||
|
version qrCodeVersion
|
||||||
|
mask int
|
||||||
|
|
||||||
|
data *bitset.Bitset
|
||||||
|
|
||||||
|
symbol *symbol
|
||||||
|
size int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abbreviated true/false.
|
||||||
|
const (
|
||||||
|
b0 = false
|
||||||
|
b1 = true
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
alignmentPatternCenter = [][]int{
|
||||||
|
{}, // Version 0 doesn't exist.
|
||||||
|
{}, // Version 1 doesn't use alignment patterns.
|
||||||
|
{6, 18},
|
||||||
|
{6, 22},
|
||||||
|
{6, 26},
|
||||||
|
{6, 30},
|
||||||
|
{6, 34},
|
||||||
|
{6, 22, 38},
|
||||||
|
{6, 24, 42},
|
||||||
|
{6, 26, 46},
|
||||||
|
{6, 28, 50},
|
||||||
|
{6, 30, 54},
|
||||||
|
{6, 32, 58},
|
||||||
|
{6, 34, 62},
|
||||||
|
{6, 26, 46, 66},
|
||||||
|
{6, 26, 48, 70},
|
||||||
|
{6, 26, 50, 74},
|
||||||
|
{6, 30, 54, 78},
|
||||||
|
{6, 30, 56, 82},
|
||||||
|
{6, 30, 58, 86},
|
||||||
|
{6, 34, 62, 90},
|
||||||
|
{6, 28, 50, 72, 94},
|
||||||
|
{6, 26, 50, 74, 98},
|
||||||
|
{6, 30, 54, 78, 102},
|
||||||
|
{6, 28, 54, 80, 106},
|
||||||
|
{6, 32, 58, 84, 110},
|
||||||
|
{6, 30, 58, 86, 114},
|
||||||
|
{6, 34, 62, 90, 118},
|
||||||
|
{6, 26, 50, 74, 98, 122},
|
||||||
|
{6, 30, 54, 78, 102, 126},
|
||||||
|
{6, 26, 52, 78, 104, 130},
|
||||||
|
{6, 30, 56, 82, 108, 134},
|
||||||
|
{6, 34, 60, 86, 112, 138},
|
||||||
|
{6, 30, 58, 86, 114, 142},
|
||||||
|
{6, 34, 62, 90, 118, 146},
|
||||||
|
{6, 30, 54, 78, 102, 126, 150},
|
||||||
|
{6, 24, 50, 76, 102, 128, 154},
|
||||||
|
{6, 28, 54, 80, 106, 132, 158},
|
||||||
|
{6, 32, 58, 84, 110, 136, 162},
|
||||||
|
{6, 26, 54, 82, 110, 138, 166},
|
||||||
|
{6, 30, 58, 86, 114, 142, 170},
|
||||||
|
}
|
||||||
|
|
||||||
|
finderPattern = [][]bool{
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b0, b0, b0, b0, b0, b1},
|
||||||
|
{b1, b0, b1, b1, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b1, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b1, b1, b0, b1},
|
||||||
|
{b1, b0, b0, b0, b0, b0, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
}
|
||||||
|
|
||||||
|
finderPatternSize = 7
|
||||||
|
|
||||||
|
finderPatternHorizontalBorder = [][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
}
|
||||||
|
|
||||||
|
finderPatternVerticalBorder = [][]bool{
|
||||||
|
{b0},
|
||||||
|
{b0},
|
||||||
|
{b0},
|
||||||
|
{b0},
|
||||||
|
{b0},
|
||||||
|
{b0},
|
||||||
|
{b0},
|
||||||
|
{b0},
|
||||||
|
}
|
||||||
|
|
||||||
|
alignmentPattern = [][]bool{
|
||||||
|
{b1, b1, b1, b1, b1},
|
||||||
|
{b1, b0, b0, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b0, b0, b1},
|
||||||
|
{b1, b1, b1, b1, b1},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildRegularSymbol(version qrCodeVersion, mask int,
|
||||||
|
data *bitset.Bitset) (*symbol, error) {
|
||||||
|
m := ®ularSymbol{
|
||||||
|
version: version,
|
||||||
|
mask: mask,
|
||||||
|
data: data,
|
||||||
|
|
||||||
|
symbol: newSymbol(version.symbolSize(), version.quietZoneSize()),
|
||||||
|
size: version.symbolSize(),
|
||||||
|
}
|
||||||
|
|
||||||
|
m.addFinderPatterns()
|
||||||
|
m.addAlignmentPatterns()
|
||||||
|
m.addTimingPatterns()
|
||||||
|
m.addFormatInfo()
|
||||||
|
m.addVersionInfo()
|
||||||
|
|
||||||
|
ok, err := m.addData()
|
||||||
|
if !ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.symbol, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *regularSymbol) addFinderPatterns() {
|
||||||
|
fpSize := finderPatternSize
|
||||||
|
fp := finderPattern
|
||||||
|
fpHBorder := finderPatternHorizontalBorder
|
||||||
|
fpVBorder := finderPatternVerticalBorder
|
||||||
|
|
||||||
|
// Top left Finder Pattern.
|
||||||
|
m.symbol.set2dPattern(0, 0, fp)
|
||||||
|
m.symbol.set2dPattern(0, fpSize, fpHBorder)
|
||||||
|
m.symbol.set2dPattern(fpSize, 0, fpVBorder)
|
||||||
|
|
||||||
|
// Top right Finder Pattern.
|
||||||
|
m.symbol.set2dPattern(m.size-fpSize, 0, fp)
|
||||||
|
m.symbol.set2dPattern(m.size-fpSize-1, fpSize, fpHBorder)
|
||||||
|
m.symbol.set2dPattern(m.size-fpSize-1, 0, fpVBorder)
|
||||||
|
|
||||||
|
// Bottom left Finder Pattern.
|
||||||
|
m.symbol.set2dPattern(0, m.size-fpSize, fp)
|
||||||
|
m.symbol.set2dPattern(0, m.size-fpSize-1, fpHBorder)
|
||||||
|
m.symbol.set2dPattern(fpSize, m.size-fpSize-1, fpVBorder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *regularSymbol) addAlignmentPatterns() {
|
||||||
|
for _, x := range alignmentPatternCenter[m.version.version] {
|
||||||
|
for _, y := range alignmentPatternCenter[m.version.version] {
|
||||||
|
if !m.symbol.empty(x, y) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
m.symbol.set2dPattern(x-2, y-2, alignmentPattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *regularSymbol) addTimingPatterns() {
|
||||||
|
value := true
|
||||||
|
|
||||||
|
for i := finderPatternSize + 1; i < m.size-finderPatternSize; i++ {
|
||||||
|
m.symbol.set(i, finderPatternSize-1, value)
|
||||||
|
m.symbol.set(finderPatternSize-1, i, value)
|
||||||
|
|
||||||
|
value = !value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *regularSymbol) addFormatInfo() {
|
||||||
|
fpSize := finderPatternSize
|
||||||
|
l := formatInfoLengthBits - 1
|
||||||
|
|
||||||
|
f := m.version.formatInfo(m.mask)
|
||||||
|
|
||||||
|
// Bits 0-7, under the top right finder pattern.
|
||||||
|
for i := 0; i <= 7; i++ {
|
||||||
|
m.symbol.set(m.size-i-1, fpSize+1, f.At(l-i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bits 0-5, right of the top left finder pattern.
|
||||||
|
for i := 0; i <= 5; i++ {
|
||||||
|
m.symbol.set(fpSize+1, i, f.At(l-i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bits 6-8 on the corner of the top left finder pattern.
|
||||||
|
m.symbol.set(fpSize+1, fpSize, f.At(l-6))
|
||||||
|
m.symbol.set(fpSize+1, fpSize+1, f.At(l-7))
|
||||||
|
m.symbol.set(fpSize, fpSize+1, f.At(l-8))
|
||||||
|
|
||||||
|
// Bits 9-14 on the underside of the top left finder pattern.
|
||||||
|
for i := 9; i <= 14; i++ {
|
||||||
|
m.symbol.set(14-i, fpSize+1, f.At(l-i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bits 8-14 on the right side of the bottom left finder pattern.
|
||||||
|
for i := 8; i <= 14; i++ {
|
||||||
|
m.symbol.set(fpSize+1, m.size-fpSize+i-8, f.At(l-i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always dark symbol.
|
||||||
|
m.symbol.set(fpSize+1, m.size-fpSize-1, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *regularSymbol) addVersionInfo() {
|
||||||
|
fpSize := finderPatternSize
|
||||||
|
|
||||||
|
v := m.version.versionInfo()
|
||||||
|
l := versionInfoLengthBits - 1
|
||||||
|
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
// Above the bottom left finder pattern.
|
||||||
|
m.symbol.set(i/3, m.size-fpSize-4+i%3, v.At(l-i))
|
||||||
|
|
||||||
|
// Left of the top right finder pattern.
|
||||||
|
m.symbol.set(m.size-fpSize-4+i%3, i/3, v.At(l-i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type direction uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
up direction = iota
|
||||||
|
down
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *regularSymbol) addData() (bool, error) {
|
||||||
|
xOffset := 1
|
||||||
|
dir := up
|
||||||
|
|
||||||
|
x := m.size - 2
|
||||||
|
y := m.size - 1
|
||||||
|
|
||||||
|
for i := 0; i < m.data.Len(); i++ {
|
||||||
|
var mask bool
|
||||||
|
switch m.mask {
|
||||||
|
case 0:
|
||||||
|
mask = (y+x+xOffset)%2 == 0
|
||||||
|
case 1:
|
||||||
|
mask = y%2 == 0
|
||||||
|
case 2:
|
||||||
|
mask = (x+xOffset)%3 == 0
|
||||||
|
case 3:
|
||||||
|
mask = (y+x+xOffset)%3 == 0
|
||||||
|
case 4:
|
||||||
|
mask = (y/2+(x+xOffset)/3)%2 == 0
|
||||||
|
case 5:
|
||||||
|
mask = (y*(x+xOffset))%2+(y*(x+xOffset))%3 == 0
|
||||||
|
case 6:
|
||||||
|
mask = ((y*(x+xOffset))%2+((y*(x+xOffset))%3))%2 == 0
|
||||||
|
case 7:
|
||||||
|
mask = ((y+x+xOffset)%2+((y*(x+xOffset))%3))%2 == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// != is equivalent to XOR.
|
||||||
|
m.symbol.set(x+xOffset, y, mask != m.data.At(i))
|
||||||
|
|
||||||
|
if i == m.data.Len()-1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find next free bit in the symbol.
|
||||||
|
for {
|
||||||
|
if xOffset == 1 {
|
||||||
|
xOffset = 0
|
||||||
|
} else {
|
||||||
|
xOffset = 1
|
||||||
|
|
||||||
|
if dir == up {
|
||||||
|
if y > 0 {
|
||||||
|
y--
|
||||||
|
} else {
|
||||||
|
dir = down
|
||||||
|
x -= 2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if y < m.size-1 {
|
||||||
|
y++
|
||||||
|
} else {
|
||||||
|
dir = up
|
||||||
|
x -= 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip over the vertical timing pattern entirely.
|
||||||
|
if x == 5 {
|
||||||
|
x--
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.symbol.empty(x+xOffset, y) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
31
vendor/github.com/skip2/go-qrcode/regular_symbol_test.go
generated
vendored
Normal file
31
vendor/github.com/skip2/go-qrcode/regular_symbol_test.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildRegularSymbol(t *testing.T) {
|
||||||
|
for k := 0; k <= 7; k++ {
|
||||||
|
v := getQRCodeVersion(Low, 1)
|
||||||
|
|
||||||
|
data := bitset.New()
|
||||||
|
for i := 0; i < 26; i++ {
|
||||||
|
data.AppendNumBools(8, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := buildRegularSymbol(*v, k, data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
} else {
|
||||||
|
_ = s
|
||||||
|
//fmt.Print(m.string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
309
vendor/github.com/skip2/go-qrcode/symbol.go
generated
vendored
Normal file
309
vendor/github.com/skip2/go-qrcode/symbol.go
generated
vendored
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
// symbol is a 2D array of bits representing a QR Code symbol.
|
||||||
|
//
|
||||||
|
// A symbol consists of size*size modules, with each module normally drawn as a
|
||||||
|
// black or white square. The symbol also has a border of quietZoneSize modules.
|
||||||
|
//
|
||||||
|
// A (fictional) size=2, quietZoneSize=1 QR Code looks like:
|
||||||
|
//
|
||||||
|
// +----+
|
||||||
|
// | |
|
||||||
|
// | ab |
|
||||||
|
// | cd |
|
||||||
|
// | |
|
||||||
|
// +----+
|
||||||
|
//
|
||||||
|
// For ease of implementation, the functions to set/get bits ignore the border,
|
||||||
|
// so (0,0)=a, (0,1)=b, (1,0)=c, and (1,1)=d. The entire symbol (including the
|
||||||
|
// border) is returned by bitmap().
|
||||||
|
//
|
||||||
|
type symbol struct {
|
||||||
|
// Value of module at [y][x]. True is set.
|
||||||
|
module [][]bool
|
||||||
|
|
||||||
|
// True if the module at [y][x] is used (to either true or false).
|
||||||
|
// Used to identify unused modules.
|
||||||
|
isUsed [][]bool
|
||||||
|
|
||||||
|
// Combined width/height of the symbol and quiet zones.
|
||||||
|
//
|
||||||
|
// size = symbolSize + 2*quietZoneSize.
|
||||||
|
size int
|
||||||
|
|
||||||
|
// Width/height of the symbol only.
|
||||||
|
symbolSize int
|
||||||
|
|
||||||
|
// Width/height of a single quiet zone.
|
||||||
|
quietZoneSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
// newSymbol constructs a symbol of size size*size, with a border of
|
||||||
|
// quietZoneSize.
|
||||||
|
func newSymbol(size int, quietZoneSize int) *symbol {
|
||||||
|
var m symbol
|
||||||
|
|
||||||
|
m.module = make([][]bool, size+2*quietZoneSize)
|
||||||
|
m.isUsed = make([][]bool, size+2*quietZoneSize)
|
||||||
|
|
||||||
|
for i := range m.module {
|
||||||
|
m.module[i] = make([]bool, size+2*quietZoneSize)
|
||||||
|
m.isUsed[i] = make([]bool, size+2*quietZoneSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.size = size + 2*quietZoneSize
|
||||||
|
m.symbolSize = size
|
||||||
|
m.quietZoneSize = quietZoneSize
|
||||||
|
|
||||||
|
return &m
|
||||||
|
}
|
||||||
|
|
||||||
|
// get returns the module value at (x, y).
|
||||||
|
func (m *symbol) get(x int, y int) (v bool) {
|
||||||
|
v = m.module[y+m.quietZoneSize][x+m.quietZoneSize]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// empty returns true if the module at (x, y) has not been set (to either true
|
||||||
|
// or false).
|
||||||
|
func (m *symbol) empty(x int, y int) bool {
|
||||||
|
return !m.isUsed[y+m.quietZoneSize][x+m.quietZoneSize]
|
||||||
|
}
|
||||||
|
|
||||||
|
// numEmptyModules returns the number of empty modules.
|
||||||
|
//
|
||||||
|
// Initially numEmptyModules is symbolSize * symbolSize. After every module has
|
||||||
|
// been set (to either true or false), the number of empty modules is zero.
|
||||||
|
func (m *symbol) numEmptyModules() int {
|
||||||
|
var count int
|
||||||
|
for y := 0; y < m.symbolSize; y++ {
|
||||||
|
for x := 0; x < m.symbolSize; x++ {
|
||||||
|
if !m.isUsed[y+m.quietZoneSize][x+m.quietZoneSize] {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// set sets the module at (x, y) to v.
|
||||||
|
func (m *symbol) set(x int, y int, v bool) {
|
||||||
|
m.module[y+m.quietZoneSize][x+m.quietZoneSize] = v
|
||||||
|
m.isUsed[y+m.quietZoneSize][x+m.quietZoneSize] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// set2dPattern sets a 2D array of modules, starting at (x, y).
|
||||||
|
func (m *symbol) set2dPattern(x int, y int, v [][]bool) {
|
||||||
|
for j, row := range v {
|
||||||
|
for i, value := range row {
|
||||||
|
m.set(x+i, y+j, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bitmap returns the entire symbol, including the quiet zone.
|
||||||
|
func (m *symbol) bitmap() [][]bool {
|
||||||
|
module := make([][]bool, len(m.module))
|
||||||
|
|
||||||
|
for i := range m.module {
|
||||||
|
module[i] = m.module[i][:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return module
|
||||||
|
}
|
||||||
|
|
||||||
|
// string returns a pictorial representation of the symbol, suitable for
|
||||||
|
// printing in a TTY.
|
||||||
|
func (m *symbol) string() string {
|
||||||
|
var result string
|
||||||
|
|
||||||
|
for _, row := range m.module {
|
||||||
|
for _, value := range row {
|
||||||
|
switch value {
|
||||||
|
case true:
|
||||||
|
result += " "
|
||||||
|
case false:
|
||||||
|
// Unicode 'FULL BLOCK' (U+2588).
|
||||||
|
result += "██"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants used to weight penalty calculations. Specified by ISO/IEC
|
||||||
|
// 18004:2006.
|
||||||
|
const (
|
||||||
|
penaltyWeight1 = 3
|
||||||
|
penaltyWeight2 = 3
|
||||||
|
penaltyWeight3 = 40
|
||||||
|
penaltyWeight4 = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
// penaltyScore returns the penalty score of the symbol. The penalty score
|
||||||
|
// consists of the sum of the four individual penalty types.
|
||||||
|
func (m *symbol) penaltyScore() int {
|
||||||
|
return m.penalty1() + m.penalty2() + m.penalty3() + m.penalty4()
|
||||||
|
}
|
||||||
|
|
||||||
|
// penalty1 returns the penalty score for "adjacent modules in row/column with
|
||||||
|
// same colour".
|
||||||
|
//
|
||||||
|
// The numbers of adjacent matching modules and scores are:
|
||||||
|
// 0-5: score = 0
|
||||||
|
// 6+ : score = penaltyWeight1 + (numAdjacentModules - 5)
|
||||||
|
func (m *symbol) penalty1() int {
|
||||||
|
penalty := 0
|
||||||
|
|
||||||
|
for x := 0; x < m.symbolSize; x++ {
|
||||||
|
lastValue := m.get(x, 0)
|
||||||
|
count := 1
|
||||||
|
|
||||||
|
for y := 1; y < m.symbolSize; y++ {
|
||||||
|
v := m.get(x, y)
|
||||||
|
|
||||||
|
if v != lastValue {
|
||||||
|
count = 1
|
||||||
|
lastValue = v
|
||||||
|
} else {
|
||||||
|
count++
|
||||||
|
if count == 6 {
|
||||||
|
penalty += penaltyWeight1 + 1
|
||||||
|
} else if count > 6 {
|
||||||
|
penalty++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for y := 0; y < m.symbolSize; y++ {
|
||||||
|
lastValue := m.get(0, y)
|
||||||
|
count := 1
|
||||||
|
|
||||||
|
for x := 1; x < m.symbolSize; x++ {
|
||||||
|
v := m.get(x, y)
|
||||||
|
|
||||||
|
if v != lastValue {
|
||||||
|
count = 1
|
||||||
|
lastValue = v
|
||||||
|
} else {
|
||||||
|
count++
|
||||||
|
if count == 6 {
|
||||||
|
penalty += penaltyWeight1 + 1
|
||||||
|
} else if count > 6 {
|
||||||
|
penalty++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return penalty
|
||||||
|
}
|
||||||
|
|
||||||
|
// penalty2 returns the penalty score for "block of modules in the same colour".
|
||||||
|
//
|
||||||
|
// m*n: score = penaltyWeight2 * (m-1) * (n-1).
|
||||||
|
func (m *symbol) penalty2() int {
|
||||||
|
penalty := 0
|
||||||
|
|
||||||
|
for y := 1; y < m.symbolSize; y++ {
|
||||||
|
for x := 1; x < m.symbolSize; x++ {
|
||||||
|
topLeft := m.get(x-1, y-1)
|
||||||
|
above := m.get(x, y-1)
|
||||||
|
left := m.get(x-1, y)
|
||||||
|
current := m.get(x, y)
|
||||||
|
|
||||||
|
if current == left && current == above && current == topLeft {
|
||||||
|
penalty++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return penalty * penaltyWeight2
|
||||||
|
}
|
||||||
|
|
||||||
|
// penalty3 returns the penalty score for "1:1:3:1:1 ratio
|
||||||
|
// (dark:light:dark:light:dark) pattern in row/column, preceded or followed by
|
||||||
|
// light area 4 modules wide".
|
||||||
|
//
|
||||||
|
// Existence of the pattern scores penaltyWeight3.
|
||||||
|
func (m *symbol) penalty3() int {
|
||||||
|
penalty := 0
|
||||||
|
|
||||||
|
for y := 0; y < m.symbolSize; y++ {
|
||||||
|
var bitBuffer int16 = 0x00
|
||||||
|
|
||||||
|
for x := 0; x < m.symbolSize; x++ {
|
||||||
|
bitBuffer <<= 1
|
||||||
|
if v := m.get(x, y); v {
|
||||||
|
bitBuffer |= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
switch bitBuffer & 0x7ff {
|
||||||
|
// 0b000 0101 1101 or 0b10111010000
|
||||||
|
// 0x05d or 0x5d0
|
||||||
|
case 0x05d, 0x5d0:
|
||||||
|
penalty += penaltyWeight3
|
||||||
|
bitBuffer = 0xFF
|
||||||
|
default:
|
||||||
|
if x == m.symbolSize-1 && (bitBuffer&0x7f) == 0x5d {
|
||||||
|
penalty += penaltyWeight3
|
||||||
|
bitBuffer = 0xFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for x := 0; x < m.symbolSize; x++ {
|
||||||
|
var bitBuffer int16 = 0x00
|
||||||
|
|
||||||
|
for y := 0; y < m.symbolSize; y++ {
|
||||||
|
bitBuffer <<= 1
|
||||||
|
if v := m.get(x, y); v {
|
||||||
|
bitBuffer |= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
switch bitBuffer & 0x7ff {
|
||||||
|
// 0b000 0101 1101 or 0b10111010000
|
||||||
|
// 0x05d or 0x5d0
|
||||||
|
case 0x05d, 0x5d0:
|
||||||
|
penalty += penaltyWeight3
|
||||||
|
bitBuffer = 0xFF
|
||||||
|
default:
|
||||||
|
if y == m.symbolSize-1 && (bitBuffer&0x7f) == 0x5d {
|
||||||
|
penalty += penaltyWeight3
|
||||||
|
bitBuffer = 0xFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return penalty
|
||||||
|
}
|
||||||
|
|
||||||
|
// penalty4 returns the penalty score...
|
||||||
|
func (m *symbol) penalty4() int {
|
||||||
|
numModules := m.symbolSize * m.symbolSize
|
||||||
|
numDarkModules := 0
|
||||||
|
|
||||||
|
for x := 0; x < m.symbolSize; x++ {
|
||||||
|
for y := 0; y < m.symbolSize; y++ {
|
||||||
|
if v := m.get(x, y); v {
|
||||||
|
numDarkModules++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numDarkModuleDeviation := numModules/2 - numDarkModules
|
||||||
|
if numDarkModuleDeviation < 0 {
|
||||||
|
numDarkModuleDeviation *= -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return penaltyWeight4 * (numDarkModuleDeviation / (numModules / 20))
|
||||||
|
}
|
334
vendor/github.com/skip2/go-qrcode/symbol_test.go
generated
vendored
Normal file
334
vendor/github.com/skip2/go-qrcode/symbol_test.go
generated
vendored
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSymbolBasic(t *testing.T) {
|
||||||
|
size := 10
|
||||||
|
quietZoneSize := 4
|
||||||
|
|
||||||
|
m := newSymbol(size, quietZoneSize)
|
||||||
|
|
||||||
|
if m.size != size+quietZoneSize*2 {
|
||||||
|
t.Errorf("Symbol size is %d, expected %d", m.size, size+quietZoneSize*2)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
for j := 0; j < size; j++ {
|
||||||
|
|
||||||
|
v := m.get(i, j)
|
||||||
|
|
||||||
|
if v != false {
|
||||||
|
t.Errorf("New symbol not empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !m.empty(i, j) {
|
||||||
|
t.Errorf("New symbol is not empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
value := i*j%2 == 0
|
||||||
|
m.set(i, j, value)
|
||||||
|
|
||||||
|
v = m.get(i, j)
|
||||||
|
|
||||||
|
if v != value {
|
||||||
|
t.Errorf("Symbol ignores set bits")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.empty(i, j) {
|
||||||
|
t.Errorf("Symbol ignores set bits")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSymbolPenalties(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
pattern [][]bool
|
||||||
|
expectedPenalty1 int
|
||||||
|
expectedPenalty2 int
|
||||||
|
expectedPenalty3 int
|
||||||
|
expectedPenalty4 int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
{b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
{b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
},
|
||||||
|
0, // No adjacent modules of same color.
|
||||||
|
0, // No 2x2+ sized blocks.
|
||||||
|
0, // No 1:1:3:1:1 pattern.
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
{b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
{b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
},
|
||||||
|
0, // 5 adjacent modules of same colour, score = 0.
|
||||||
|
0, // No 2x2+ sized blocks.
|
||||||
|
0, // No 1:1:3:1:1 pattern.
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b0},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
{b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
{b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
},
|
||||||
|
4, // 6 adjacent modules of same colour, score = 3 + (6-5)
|
||||||
|
0, // No 2x2+ sized blocks.
|
||||||
|
0, // No 1:1:3:1:1 pattern.
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b1, b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b0, b0, b0, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b0, b0, b0, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b0, b0, b0, b0, b0},
|
||||||
|
},
|
||||||
|
28, // 3+(7-5) + 3+(6-5) + 3+(6-5) + 3+(6-5) + 3+(7-5) + 3+(7-5) = 28
|
||||||
|
0, // No 2x2+ sized blocks.
|
||||||
|
0, // No 1:1:3:1:1 pattern.
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b1, b0, b1},
|
||||||
|
{b0, b0, b1, b0, b1, b0},
|
||||||
|
{b0, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b1, b1, b0},
|
||||||
|
{b0, b1, b1, b1, b0, b1},
|
||||||
|
{b1, b0, b1, b0, b1, b0},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
6, // 3*(2-1)*(2-1) + 3(2-1)*(2-1)
|
||||||
|
0, // No 1:1:3:1:1 pattern.
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b1},
|
||||||
|
{b0, b0, b0, b0, b0, b1},
|
||||||
|
{b0, b0, b0, b0, b0, b1},
|
||||||
|
{b0, b0, b0, b0, b0, b1},
|
||||||
|
{b0, b0, b0, b0, b0, b1},
|
||||||
|
{b0, b0, b0, b0, b0, b1},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
60, // 3 * (5-1) * (6-1)
|
||||||
|
0, // No 1:1:3:1:1 pattern.
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b1},
|
||||||
|
{b0, b0, b0, b0, b0, b1},
|
||||||
|
{b1, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b1, b0, b1, b0, b1},
|
||||||
|
{b1, b1, b0, b1, b0, b1},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
21, // 3*(5-1)*(2-1) + 3*(2-1)*(4-1) = 3*4 + 3*3
|
||||||
|
0, // No 1:1:3:1:1 pattern.
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
480, // 12* 1:1:3:1:1 patterns, 12 * 40.
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b1, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b1, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
80, // 2* 1:1:3:1:1 patterns, 2 * 40.
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
100, // 10 * (10 steps of 5% deviation from 50% black/white).
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
100, // 10 * (10 steps of 5% deviation from 50% black/white).
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
0, // Exactly 50%/50% black/white.
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
20, // 10 * (2 steps of 5% deviation towards white).
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
30, // 10 * (3 steps of 5% deviation towards white).
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[][]bool{
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
|
||||||
|
{b0, b0, b0, b0, b0, b0, b0, b0, b0, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
30, // 10 * (3 steps of 5% deviation towards white).
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
s := newSymbol(len(test.pattern[0]), 4)
|
||||||
|
s.set2dPattern(0, 0, test.pattern)
|
||||||
|
|
||||||
|
penalty1 := s.penalty1()
|
||||||
|
penalty2 := s.penalty2()
|
||||||
|
penalty3 := s.penalty3()
|
||||||
|
penalty4 := s.penalty4()
|
||||||
|
|
||||||
|
ok := true
|
||||||
|
|
||||||
|
if test.expectedPenalty1 != -1 && test.expectedPenalty1 != penalty1 {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
if test.expectedPenalty2 != -1 && test.expectedPenalty2 != penalty2 {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
if test.expectedPenalty3 != -1 && test.expectedPenalty3 != penalty3 {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
if test.expectedPenalty4 != -1 && test.expectedPenalty4 != penalty4 {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Penalty test #%d p1=%d, p2=%d, p3=%d, p4=%d (expected p1=%d, p2=%d, p3=%d, p4=%d)", i, penalty1, penalty2, penalty3, penalty4,
|
||||||
|
test.expectedPenalty1, test.expectedPenalty2, test.expectedPenalty3,
|
||||||
|
test.expectedPenalty4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3050
vendor/github.com/skip2/go-qrcode/version.go
generated
vendored
Normal file
3050
vendor/github.com/skip2/go-qrcode/version.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
158
vendor/github.com/skip2/go-qrcode/version_test.go
generated
vendored
Normal file
158
vendor/github.com/skip2/go-qrcode/version_test.go
generated
vendored
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
// go-qrcode
|
||||||
|
// Copyright 2014 Tom Harwood
|
||||||
|
|
||||||
|
package qrcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormatInfo(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
level RecoveryLevel
|
||||||
|
maskPattern int
|
||||||
|
|
||||||
|
expected uint32
|
||||||
|
}{
|
||||||
|
{ // L=01 M=00 Q=11 H=10
|
||||||
|
Low,
|
||||||
|
1,
|
||||||
|
0x72f3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Medium,
|
||||||
|
2,
|
||||||
|
0x5e7c,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
High,
|
||||||
|
3,
|
||||||
|
0x3a06,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Highest,
|
||||||
|
4,
|
||||||
|
0x0762,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Low,
|
||||||
|
5,
|
||||||
|
0x6318,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Medium,
|
||||||
|
6,
|
||||||
|
0x4f97,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
High,
|
||||||
|
7,
|
||||||
|
0x2bed,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
v := getQRCodeVersion(test.level, 1)
|
||||||
|
|
||||||
|
result := v.formatInfo(test.maskPattern)
|
||||||
|
|
||||||
|
expected := bitset.New()
|
||||||
|
expected.AppendUint32(test.expected, formatInfoLengthBits)
|
||||||
|
|
||||||
|
if !expected.Equals(result) {
|
||||||
|
t.Errorf("formatInfo test #%d got %s, expected %s", i, result.String(),
|
||||||
|
expected.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVersionInfo(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
version int
|
||||||
|
expected uint32
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
7,
|
||||||
|
0x007c94,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
10,
|
||||||
|
0x00a4d3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
20,
|
||||||
|
0x0149a6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
30,
|
||||||
|
0x01ed75,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
40,
|
||||||
|
0x028c69,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
var v *qrCodeVersion
|
||||||
|
|
||||||
|
v = getQRCodeVersion(Low, test.version)
|
||||||
|
|
||||||
|
result := v.versionInfo()
|
||||||
|
|
||||||
|
expected := bitset.New()
|
||||||
|
expected.AppendUint32(test.expected, versionInfoLengthBits)
|
||||||
|
|
||||||
|
if !expected.Equals(result) {
|
||||||
|
t.Errorf("versionInfo test #%d got %s, expected %s", i, result.String(),
|
||||||
|
expected.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNumBitsToPadToCodeoword(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
level RecoveryLevel
|
||||||
|
version int
|
||||||
|
|
||||||
|
numDataBits int
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Low,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
}, {
|
||||||
|
Low,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
7,
|
||||||
|
}, {
|
||||||
|
Low,
|
||||||
|
1,
|
||||||
|
7,
|
||||||
|
1,
|
||||||
|
}, {
|
||||||
|
Low,
|
||||||
|
1,
|
||||||
|
8,
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
var v *qrCodeVersion
|
||||||
|
|
||||||
|
v = getQRCodeVersion(test.level, test.version)
|
||||||
|
|
||||||
|
result := v.numBitsToPadToCodeword(test.numDataBits)
|
||||||
|
|
||||||
|
if result != test.expected {
|
||||||
|
t.Errorf("numBitsToPadToCodeword test %d (version=%d numDataBits=%d), got %d, expected %d",
|
||||||
|
i, test.version, test.numDataBits, result, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user