├── .travis.yml ├── COPYING ├── README.md ├── example └── qr-png.go └── qrencode ├── bits.go ├── boolbits.go ├── bytebits.go ├── content.go ├── encode.go ├── errorcorrection.go ├── int32bits.go ├── mode.go ├── qr_test.go ├── qrgrid.go └── version.go /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | script: go test -v ./qrencode/... 3 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QR encoder in Go based on the ZXing encoder (http://code.google.com/p/zxing/). 2 | 3 | [![GoDoc](https://godoc.org/github.com/qpliu/qrencode-go/qrencode?status.svg)](https://godoc.org/github.com/qpliu/qrencode-go/qrencode) 4 | [![Build Status](https://travis-ci.org/qpliu/qrencode-go.svg?branch=master)](https://travis-ci.org/qpliu/qrencode-go) 5 | 6 | I was surprised that I couldn't find a QR encoder in Go, especially 7 | since the example at http://golang.org/doc/effective_go.html#web_server 8 | is a QR code generator, though the QR encoding is done by an external 9 | Google service in the example. 10 | 11 | # Example 12 | 13 | ```go 14 | package main 15 | 16 | import ( 17 | "bytes" 18 | "image/png" 19 | "os" 20 | 21 | "github.com/qpliu/qrencode-go/qrencode" 22 | ) 23 | 24 | func main() { 25 | var buf bytes.Buffer 26 | for i, arg := range os.Args { 27 | if i > 1 { 28 | if err := buf.WriteByte(' '); err != nil { 29 | panic(err) 30 | } 31 | } 32 | if i > 0 { 33 | if _, err := buf.WriteString(arg); err != nil { 34 | panic(err) 35 | } 36 | } 37 | } 38 | grid, err := qrencode.Encode(buf.String(), qrencode.ECLevelQ) 39 | if err != nil { 40 | panic(err) 41 | } 42 | png.Encode(os.Stdout, grid.Image(8)) 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /example/qr-png.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "image/png" 6 | "os" 7 | 8 | "github.com/qpliu/qrencode-go/qrencode" 9 | ) 10 | 11 | func main() { 12 | var buf bytes.Buffer 13 | for i, arg := range os.Args { 14 | if i > 1 { 15 | if err := buf.WriteByte(' '); err != nil { 16 | panic(err) 17 | } 18 | } 19 | if i > 0 { 20 | if _, err := buf.WriteString(arg); err != nil { 21 | panic(err) 22 | } 23 | } 24 | } 25 | grid, err := qrencode.Encode(buf.String(), qrencode.ECLevelQ) 26 | if err != nil { 27 | panic(err) 28 | } 29 | png.Encode(os.Stdout, grid.Image(8)) 30 | } 31 | -------------------------------------------------------------------------------- /qrencode/bits.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | import ( 4 | "bytes" 5 | "image" 6 | "image/color" 7 | "io" 8 | ) 9 | 10 | // The test benchmark shows that encoding with boolBitVector/boolBitGrid is 11 | // twice as fast as byteBitVector/byteBitGrid and uin32BitVector/uint32BitGrid. 12 | 13 | type BitVector struct { 14 | boolBitVector 15 | } 16 | 17 | type BitGrid struct { 18 | boolBitGrid 19 | } 20 | 21 | func (v *BitVector) AppendBits(b BitVector) { 22 | v.boolBitVector.AppendBits(b.boolBitVector) 23 | } 24 | 25 | func NewBitGrid(width, height int) *BitGrid { 26 | return &BitGrid{newBoolBitGrid(width, height)} 27 | } 28 | 29 | /* 30 | type BitVector struct { 31 | byteBitVector 32 | } 33 | 34 | type BitGrid struct { 35 | byteBitGrid 36 | } 37 | 38 | func (v *BitVector) AppendBits(b BitVector) { 39 | v.byteBitVector.AppendBits(b.byteBitVector) 40 | } 41 | 42 | func NewBitGrid(width, height int) *BitGrid { 43 | return &BitGrid{newByteBitGrid(width, height)} 44 | } 45 | */ 46 | 47 | /* 48 | type BitVector struct { 49 | uint32BitVector 50 | } 51 | 52 | type BitGrid struct { 53 | uint32BitGrid 54 | } 55 | 56 | func (v *BitVector) AppendBits(b BitVector) { 57 | v.uint32BitVector.AppendBits(b.uint32BitVector) 58 | } 59 | 60 | func NewBitGrid(width, height int) *BitGrid { 61 | return &BitGrid{newUint32BitGrid(width, height)} 62 | } 63 | */ 64 | 65 | func (v *BitVector) String() string { 66 | b := bytes.Buffer{} 67 | for i, l := 0, v.Length(); i < l; i++ { 68 | if v.Get(i) { 69 | b.WriteString("1") 70 | } else { 71 | b.WriteString("0") 72 | } 73 | } 74 | return b.String() 75 | } 76 | 77 | func (g *BitGrid) String() string { 78 | b := bytes.Buffer{} 79 | for y, w, h := 0, g.Width(), g.Height(); y < h; y++ { 80 | for x := 0; x < w; x++ { 81 | if g.Empty(x, y) { 82 | b.WriteString(" ") 83 | } else if g.Get(x, y) { 84 | b.WriteString("#") 85 | } else { 86 | b.WriteString("_") 87 | } 88 | } 89 | b.WriteString("\n") 90 | } 91 | return b.String() 92 | } 93 | 94 | // Encode the Grid in ANSI escape sequences and set the background according 95 | // to the values in the BitGrid surrounded by a white frame 96 | func (g *BitGrid) TerminalOutput(w io.Writer) { 97 | white := "\033[47m \033[0m" 98 | black := "\033[40m \033[0m" 99 | newline := "\n" 100 | 101 | w.Write([]byte(white)) 102 | for i := 0; i <= g.Width(); i++ { 103 | w.Write([]byte(white)) 104 | } 105 | w.Write([]byte(newline)) 106 | 107 | for i := 0; i < g.Height(); i++ { 108 | w.Write([]byte(white)) 109 | for j := 0; j < g.Width(); j++ { 110 | if g.Get(j, i) { 111 | w.Write([]byte(black)) 112 | } else { 113 | w.Write([]byte(white)) 114 | } 115 | } 116 | w.Write([]byte(white)) 117 | w.Write([]byte(newline)) 118 | } 119 | w.Write([]byte(white)) 120 | for i := 0; i <= g.Width(); i++ { 121 | w.Write([]byte(white)) 122 | } 123 | w.Write([]byte(newline)) 124 | } 125 | 126 | // Return an image of the grid, with black blocks for true items and 127 | // white blocks for false items, with the given block size and a 128 | // default margin. 129 | func (g *BitGrid) Image(blockSize int) image.Image { 130 | return g.ImageWithMargin(blockSize, 4) 131 | } 132 | 133 | // Return an image of the grid, with black blocks for true items and 134 | // white blocks for false items, with the given block size and margin. 135 | func (g *BitGrid) ImageWithMargin(blockSize, margin int) image.Image { 136 | width := blockSize * (2*margin + g.Width()) 137 | height := blockSize * (2*margin + g.Height()) 138 | i := image.NewGray16(image.Rect(0, 0, width, height)) 139 | for y := 0; y < blockSize*margin; y++ { 140 | for x := 0; x < width; x++ { 141 | i.Set(x, y, color.White) 142 | i.Set(x, height-1-y, color.White) 143 | } 144 | } 145 | for y := blockSize * margin; y < height-blockSize*margin; y++ { 146 | for x := 0; x < blockSize*margin; x++ { 147 | i.Set(x, y, color.White) 148 | i.Set(width-1-x, y, color.White) 149 | } 150 | } 151 | for y, w, h := 0, g.Width(), g.Height(); y < h; y++ { 152 | for x := 0; x < w; x++ { 153 | x0 := blockSize * (x + margin) 154 | y0 := blockSize * (y + margin) 155 | c := color.White 156 | if g.Get(x, y) { 157 | c = color.Black 158 | } 159 | for dy := 0; dy < blockSize; dy++ { 160 | for dx := 0; dx < blockSize; dx++ { 161 | i.Set(x0+dx, y0+dy, c) 162 | } 163 | } 164 | } 165 | } 166 | return i 167 | } 168 | -------------------------------------------------------------------------------- /qrencode/boolbits.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | type boolBitVector struct { 4 | bits []bool 5 | } 6 | 7 | func (v *boolBitVector) Length() int { 8 | return len(v.bits) 9 | } 10 | 11 | func (v *boolBitVector) Get(i int) bool { 12 | return v.bits[i] 13 | } 14 | 15 | func (v *boolBitVector) AppendBit(b bool) { 16 | v.bits = append(v.bits, b) 17 | } 18 | 19 | func (v *boolBitVector) Append(b, count int) { 20 | for i := uint(count); i > 0; i-- { 21 | v.AppendBit((b>>(i-1))&1 == 1) 22 | } 23 | } 24 | 25 | func (v *boolBitVector) AppendBits(b boolBitVector) { 26 | v.bits = append(v.bits, b.bits...) 27 | } 28 | 29 | type boolBitGrid struct { 30 | width, height int 31 | bits []bool 32 | } 33 | 34 | func newBoolBitGrid(width, height int) boolBitGrid { 35 | return boolBitGrid{width, height, make([]bool, 2*width*height)} 36 | } 37 | 38 | func (g *boolBitGrid) Width() int { 39 | return g.width 40 | } 41 | 42 | func (g *boolBitGrid) Height() int { 43 | return g.height 44 | } 45 | 46 | func (g *boolBitGrid) Empty(x, y int) bool { 47 | return !g.bits[2*(x+y*g.width)] 48 | } 49 | 50 | func (g *boolBitGrid) Get(x, y int) bool { 51 | return g.bits[2*(x+y*g.width)+1] 52 | } 53 | 54 | func (g *boolBitGrid) Set(x, y int, v bool) { 55 | g.bits[2*(x+y*g.width)] = true 56 | g.bits[2*(x+y*g.width)+1] = v 57 | } 58 | 59 | func (g *boolBitGrid) Clear() { 60 | for i, _ := range g.bits { 61 | g.bits[i] = false 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /qrencode/bytebits.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | type byteBitVector struct { 4 | bitIndex byte 5 | bits []byte 6 | } 7 | 8 | func (v *byteBitVector) Length() int { 9 | if v.bitIndex == 0 { 10 | return len(v.bits) * 8 11 | } 12 | return (len(v.bits)-1)*8 + int(v.bitIndex) 13 | } 14 | 15 | func (v *byteBitVector) Get(i int) bool { 16 | return (v.bits[i/8]>>uint(i%8))&1 == 1 17 | } 18 | 19 | func (v *byteBitVector) AppendBit(b bool) { 20 | if v.bitIndex == 0 { 21 | v.bits = append(v.bits, 0) 22 | } 23 | if b { 24 | v.bits[len(v.bits)-1] |= 1 << v.bitIndex 25 | } else { 26 | v.bits[len(v.bits)-1] &= 255 ^ (1 << v.bitIndex) 27 | } 28 | v.bitIndex++ 29 | v.bitIndex %= 8 30 | } 31 | 32 | func (v *byteBitVector) Append(b, count int) { 33 | for i := uint(count); i > 0; i-- { 34 | v.AppendBit((b>>(i-1))&1 == 1) 35 | } 36 | } 37 | 38 | func (v *byteBitVector) AppendBits(b byteBitVector) { 39 | if v.bitIndex == 0 { 40 | v.bitIndex = b.bitIndex 41 | v.bits = append(v.bits, b.bits...) 42 | } else { 43 | for i, l := 0, b.Length(); i < l; i++ { 44 | v.AppendBit(b.Get(i)) 45 | } 46 | } 47 | } 48 | 49 | type byteBitGrid struct { 50 | width, height int 51 | bits []byte 52 | } 53 | 54 | func newByteBitGrid(width, height int) byteBitGrid { 55 | return byteBitGrid{width, height, make([]byte, (2*width*height+7)/8)} 56 | } 57 | 58 | func (g *byteBitGrid) Width() int { 59 | return g.width 60 | } 61 | 62 | func (g *byteBitGrid) Height() int { 63 | return g.height 64 | } 65 | 66 | func (g *byteBitGrid) Empty(x, y int) bool { 67 | i := 2 * (x + y*g.width) 68 | return (g.bits[i/8]>>uint(i%8))&1 == 0 69 | } 70 | 71 | func (g *byteBitGrid) Get(x, y int) bool { 72 | i := 2*(x+y*g.width) + 1 73 | return (g.bits[i/8]>>uint(i%8))&1 == 0 74 | } 75 | 76 | func (g *byteBitGrid) Set(x, y int, v bool) { 77 | i := 2 * (x + y*g.width) 78 | if v { 79 | g.bits[i/8] |= 3 << uint(i%8) 80 | } else { 81 | g.bits[i/8] |= 1 << uint(i%8) 82 | g.bits[i/8] &= 255 ^ (1 << uint(i%8+1)) 83 | } 84 | } 85 | 86 | func (g *byteBitGrid) Clear() { 87 | for i, _ := range g.bits { 88 | g.bits[i] = 0 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /qrencode/content.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | func stringContentBits(content string, ecLevel ECLevel) (*BitVector, versionNumber, error) { 8 | if !supportedECLevel(ecLevel) { 9 | return nil, versionNumber(0), errors.New("Unrecognized ECLevel") 10 | } 11 | headerBits := &BitVector{} 12 | mode := getMode(content) 13 | if mode == modeByte { 14 | headerBits.Append(int(modeECI), 4) 15 | headerBits.Append(26, 8) // UTF-8 16 | } 17 | headerBits.Append(int(mode), 4) 18 | return contentBits([]byte(content), ecLevel, mode, headerBits) 19 | } 20 | 21 | func binaryContentBits(content []byte, ecLevel ECLevel) (*BitVector, versionNumber, error) { 22 | if !supportedECLevel(ecLevel) { 23 | return nil, versionNumber(0), errors.New("Unrecognized ECLevel") 24 | } 25 | headerBits := &BitVector{} 26 | headerBits.Append(int(modeByte), 4) 27 | return contentBits(content, ecLevel, modeByte, headerBits) 28 | } 29 | 30 | func contentBits(content []byte, ecLevel ECLevel, mode modeIndicator, headerBits *BitVector) (*BitVector, versionNumber, error) { 31 | dataBits := BitVector{} 32 | appendContent(content, mode, &dataBits) 33 | 34 | bitsNeeded := headerBits.Length() + dataBits.Length() + mode.characterCountBits(versionNumber(40)) 35 | version, err := chooseVersion(bitsNeeded, ecLevel) 36 | if err != nil { 37 | return nil, version, err 38 | } 39 | 40 | headerAndDataBits := &BitVector{} 41 | headerAndDataBits.AppendBits(*headerBits) 42 | headerAndDataBits.Append(len(content), mode.characterCountBits(version)) 43 | headerAndDataBits.AppendBits(dataBits) 44 | 45 | appendTerminator(version.totalCodewords()-ecBlocks[version][ecLevel].totalECCodewords(), headerAndDataBits) 46 | return headerAndDataBits, version, nil 47 | } 48 | 49 | var ( 50 | invalidAlphanumericByte = errors.New("Invalid Alphanumeric Byte") 51 | ) 52 | 53 | func alphanumericCode(b byte) (byte, error) { 54 | switch b { 55 | case 0x30: 56 | return 0, nil 57 | case 0x31: 58 | return 1, nil 59 | case 0x32: 60 | return 2, nil 61 | case 0x33: 62 | return 3, nil 63 | case 0x34: 64 | return 4, nil 65 | case 0x35: 66 | return 5, nil 67 | case 0x36: 68 | return 6, nil 69 | case 0x37: 70 | return 7, nil 71 | case 0x38: 72 | return 8, nil 73 | case 0x39: 74 | return 9, nil 75 | case 0x41: 76 | return 10, nil 77 | case 0x42: 78 | return 11, nil 79 | case 0x43: 80 | return 12, nil 81 | case 0x44: 82 | return 13, nil 83 | case 0x45: 84 | return 14, nil 85 | case 0x46: 86 | return 15, nil 87 | case 0x47: 88 | return 16, nil 89 | case 0x48: 90 | return 17, nil 91 | case 0x49: 92 | return 18, nil 93 | case 0x4a: 94 | return 19, nil 95 | case 0x4b: 96 | return 20, nil 97 | case 0x4c: 98 | return 21, nil 99 | case 0x4d: 100 | return 22, nil 101 | case 0x4e: 102 | return 23, nil 103 | case 0x4f: 104 | return 24, nil 105 | case 0x50: 106 | return 25, nil 107 | case 0x51: 108 | return 26, nil 109 | case 0x52: 110 | return 27, nil 111 | case 0x53: 112 | return 28, nil 113 | case 0x54: 114 | return 29, nil 115 | case 0x55: 116 | return 30, nil 117 | case 0x56: 118 | return 31, nil 119 | case 0x57: 120 | return 32, nil 121 | case 0x58: 122 | return 33, nil 123 | case 0x59: 124 | return 34, nil 125 | case 0x5a: 126 | return 35, nil 127 | case 0x20: 128 | return 36, nil 129 | case 0x24: 130 | return 37, nil 131 | case 0x25: 132 | return 38, nil 133 | case 0x2a: 134 | return 39, nil 135 | case 0x2b: 136 | return 40, nil 137 | case 0x2d: 138 | return 41, nil 139 | case 0x2e: 140 | return 42, nil 141 | case 0x2f: 142 | return 43, nil 143 | case 0x3a: 144 | return 44, nil 145 | } 146 | return 0, invalidAlphanumericByte 147 | } 148 | 149 | func appendContent(content []byte, mode modeIndicator, bits *BitVector) { 150 | switch mode { 151 | case modeNumeric: 152 | for i := 0; i+2 < len(content); i += 3 { 153 | n1, err := alphanumericCode(content[i]) 154 | if n1 > 9 || err != nil { 155 | panic("Invalid numeric mode content") 156 | } 157 | n2, err := alphanumericCode(content[i+1]) 158 | if n2 > 9 || err != nil { 159 | panic("Invalid numeric mode content") 160 | } 161 | n3, err := alphanumericCode(content[i+2]) 162 | if n3 > 9 || err != nil { 163 | panic("Invalid numeric mode content") 164 | } 165 | bits.Append(int(n1)*100+int(n2)*10+int(n3), 10) 166 | } 167 | switch len(content) % 3 { 168 | case 1: 169 | n1, err := alphanumericCode(content[len(content)-1]) 170 | if n1 > 9 || err != nil { 171 | panic("Invalid numeric mode content") 172 | } 173 | bits.Append(int(n1), 4) 174 | case 2: 175 | n1, err := alphanumericCode(content[len(content)-2]) 176 | if n1 > 9 || err != nil { 177 | panic("Invalid numeric mode content") 178 | } 179 | n2, err := alphanumericCode(content[len(content)-1]) 180 | if n2 > 9 || err != nil { 181 | panic("Invalid numeric mode content") 182 | } 183 | bits.Append(int(n1)*10+int(n2), 7) 184 | } 185 | case modeAlphanumeric: 186 | for i := 0; i+1 < len(content); i += 2 { 187 | n1, err := alphanumericCode(content[i]) 188 | if err != nil { 189 | panic("Invalid alphanumeric mode content") 190 | } 191 | n2, err := alphanumericCode(content[i+1]) 192 | if err != nil { 193 | panic("Invalid alphanumeric mode content") 194 | } 195 | bits.Append(int(n1)*45+int(n2), 11) 196 | } 197 | if len(content)%2 == 1 { 198 | n1, err := alphanumericCode(content[len(content)-1]) 199 | if err != nil { 200 | panic("Invalid alphanumeric mode content") 201 | } 202 | bits.Append(int(n1), 6) 203 | } 204 | case modeByte: 205 | for _, b := range content { 206 | bits.Append(int(b), 8) 207 | } 208 | default: 209 | panic("Unsupported mode") 210 | } 211 | } 212 | 213 | func appendTerminator(capacityBytes int, bits *BitVector) { 214 | capacity := capacityBytes * 8 215 | if bits.Length() > capacity { 216 | panic("bits.Length() > capacity") 217 | } 218 | for i := 0; i < 4 && bits.Length() < capacity; i++ { 219 | bits.AppendBit(false) 220 | } 221 | if bits.Length()%8 != 0 { 222 | for i := bits.Length() % 8; i < 8; i++ { 223 | bits.AppendBit(false) 224 | } 225 | } 226 | for { 227 | if bits.Length() >= capacity { 228 | break 229 | } 230 | bits.Append(0xec, 8) 231 | if bits.Length() >= capacity { 232 | break 233 | } 234 | bits.Append(0x11, 8) 235 | } 236 | if bits.Length() != capacity { 237 | panic("bits.Length() != capacity") 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /qrencode/encode.go: -------------------------------------------------------------------------------- 1 | // Package qrencode provides functions to generate QR codes. 2 | package qrencode 3 | 4 | // QR encode the content at the specified error correction level (ecLevel). 5 | func Encode(content string, ecLevel ECLevel) (*BitGrid, error) { 6 | bits, version, err := stringContentBits(content, ecLevel) 7 | if err != nil { 8 | return nil, err 9 | } 10 | return encode(bits, version, ecLevel) 11 | } 12 | 13 | // QR encode the content at the specified error correction level (ecLevel). 14 | func EncodeBytes(content []byte, ecLevel ECLevel) (*BitGrid, error) { 15 | bits, version, err := binaryContentBits(content, ecLevel) 16 | if err != nil { 17 | return nil, err 18 | } 19 | return encode(bits, version, ecLevel) 20 | } 21 | 22 | func encode(bits *BitVector, version versionNumber, ecLevel ECLevel) (*BitGrid, error) { 23 | bits = interleaveWithECBytes(bits, version, ecLevel) 24 | grid := NewBitGrid(version.dimension(), version.dimension()) 25 | maskPattern := bestMaskPattern(bits, version, ecLevel, grid) 26 | buildGrid(bits, version, ecLevel, maskPattern, grid) 27 | return grid, nil 28 | } 29 | -------------------------------------------------------------------------------- /qrencode/errorcorrection.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | type ECLevel int 4 | 5 | const ( 6 | ECLevelM = ECLevel(0) 7 | ECLevelL = ECLevel(1) 8 | ECLevelH = ECLevel(2) 9 | ECLevelQ = ECLevel(3) 10 | ) 11 | 12 | func supportedECLevel(ecLevel ECLevel) bool { 13 | switch ecLevel { 14 | case ECLevelM, ECLevelL, ECLevelH, ECLevelQ: 15 | return true 16 | } 17 | return false 18 | } 19 | 20 | type blockPair struct { 21 | dataBytes, ecBytes []int 22 | } 23 | 24 | func interleaveWithECBytes(bits *BitVector, version versionNumber, ecLevel ECLevel) *BitVector { 25 | numTotalBytes := version.totalCodewords() 26 | numDataBytes := version.totalCodewords() - ecBlocks[version][ecLevel].totalECCodewords() 27 | numRSBlocks := ecBlocks[version][ecLevel].numBlocks() 28 | if bits.Length() != numDataBytes*8 { 29 | panic("bits.Length() != numDataBytes*8") 30 | } 31 | 32 | dataBytesOffset := 0 33 | maxNumDataBytes := 0 34 | maxNumEcBytes := 0 35 | 36 | blocks := make([]blockPair, numRSBlocks) 37 | 38 | for i := 0; i < numRSBlocks; i++ { 39 | numDataBytes, numEcBytes := getBlockSizes(numTotalBytes, numDataBytes, numRSBlocks, i) 40 | blocks[i] = blockPair{make([]int, numDataBytes), make([]int, numEcBytes)} 41 | for j := 0; j < numDataBytes; j++ { 42 | blocks[i].dataBytes[j] = 0 43 | if bits.Get(8 * (dataBytesOffset + j)) { 44 | blocks[i].dataBytes[j] |= 128 45 | } 46 | if bits.Get(8*(dataBytesOffset+j) + 1) { 47 | blocks[i].dataBytes[j] |= 64 48 | } 49 | if bits.Get(8*(dataBytesOffset+j) + 2) { 50 | blocks[i].dataBytes[j] |= 32 51 | } 52 | if bits.Get(8*(dataBytesOffset+j) + 3) { 53 | blocks[i].dataBytes[j] |= 16 54 | } 55 | if bits.Get(8*(dataBytesOffset+j) + 4) { 56 | blocks[i].dataBytes[j] |= 8 57 | } 58 | if bits.Get(8*(dataBytesOffset+j) + 5) { 59 | blocks[i].dataBytes[j] |= 4 60 | } 61 | if bits.Get(8*(dataBytesOffset+j) + 6) { 62 | blocks[i].dataBytes[j] |= 2 63 | } 64 | if bits.Get(8*(dataBytesOffset+j) + 7) { 65 | blocks[i].dataBytes[j] |= 1 66 | } 67 | } 68 | generateECBytes(&blocks[i]) 69 | 70 | if numDataBytes > maxNumDataBytes { 71 | maxNumDataBytes = numDataBytes 72 | } 73 | if numEcBytes > maxNumEcBytes { 74 | maxNumEcBytes = numEcBytes 75 | } 76 | dataBytesOffset += numDataBytes 77 | } 78 | 79 | if numDataBytes != dataBytesOffset { 80 | panic("numDataBytes != dataBytesOffset") 81 | } 82 | 83 | result := &BitVector{} 84 | for i := 0; i < maxNumDataBytes; i++ { 85 | for _, block := range blocks { 86 | if i < len(block.dataBytes) { 87 | result.Append(block.dataBytes[i], 8) 88 | } 89 | } 90 | } 91 | for i := 0; i < maxNumEcBytes; i++ { 92 | for _, block := range blocks { 93 | if i < len(block.ecBytes) { 94 | result.Append(block.ecBytes[i], 8) 95 | } 96 | } 97 | } 98 | 99 | if result.Length() != numTotalBytes*8 { 100 | panic("result.Length() != numTotalBytes*8") 101 | } 102 | return result 103 | } 104 | 105 | func getBlockSizes(numTotalBytes, numDataBytes, numRSBlocks, blockID int) (int, int) { 106 | if blockID >= numRSBlocks { 107 | panic("blockID >= numRSBlocks") 108 | } 109 | numRsBlocksInGroup2 := numTotalBytes % numRSBlocks 110 | numRsBlocksInGroup1 := numRSBlocks - numRsBlocksInGroup2 111 | numTotalBytesInGroup1 := numTotalBytes / numRSBlocks 112 | numTotalBytesInGroup2 := numTotalBytesInGroup1 + 1 113 | numDataBytesInGroup1 := numDataBytes / numRSBlocks 114 | numDataBytesInGroup2 := numDataBytesInGroup1 + 1 115 | numEcBytesInGroup1 := numTotalBytesInGroup1 - numDataBytesInGroup1 116 | numEcBytesInGroup2 := numTotalBytesInGroup2 - numDataBytesInGroup2 117 | if numEcBytesInGroup1 != numEcBytesInGroup2 { 118 | panic("numEcBytesInGroup1 != numEcBytesInGroup2") 119 | } 120 | if numRSBlocks != numRsBlocksInGroup1+numRsBlocksInGroup2 { 121 | panic("numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2") 122 | } 123 | if numTotalBytes != (numDataBytesInGroup1+numEcBytesInGroup1)*numRsBlocksInGroup1+(numDataBytesInGroup2+numEcBytesInGroup2)*numRsBlocksInGroup2 { 124 | panic("numTotalBytes != (numDataBytesInGroup1 + numEcBytesInGroup1)*numRsBlocksInGroup1 + (numDataBytesInGroup2 + numEcBytesInGroup2)*numRsBlocksInGroup2") 125 | } 126 | if blockID < numRsBlocksInGroup1 { 127 | return numDataBytesInGroup1, numEcBytesInGroup1 128 | } 129 | return numDataBytesInGroup2, numEcBytesInGroup2 130 | } 131 | 132 | func generateECBytes(block *blockPair) { 133 | generator := buildGenerator(len(block.ecBytes)) 134 | info := newGFPoly(block.dataBytes) 135 | info = info.MultiplyByMonomial(len(block.ecBytes), 1) 136 | _, remainder := info.Divide(generator) 137 | numZeroCoefficients := len(block.ecBytes) - len(remainder.coefficients) 138 | for i := 0; i < numZeroCoefficients; i++ { 139 | block.ecBytes[i] = 0 140 | } 141 | copy(block.ecBytes[numZeroCoefficients:], remainder.coefficients) 142 | } 143 | 144 | var ( 145 | fieldExpTable = [256]int{ 146 | 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 147 | 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 148 | 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 149 | 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 150 | 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 151 | 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 152 | 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 153 | 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 154 | 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 155 | 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 156 | 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 157 | 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 158 | 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 159 | 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 160 | 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 161 | 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 162 | } 163 | fieldLogTable = [256]int{ 164 | 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 165 | 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 166 | 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 167 | 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 168 | 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 169 | 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 170 | 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 171 | 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 172 | 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 173 | 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 174 | 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 175 | 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 176 | 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 177 | 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 178 | 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 179 | 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175, 180 | } 181 | fieldZero = gfPoly{[]int{0}} 182 | cachedGenerators = []gfPoly{gfPoly{[]int{1}}} 183 | ) 184 | 185 | func fieldAddSub(a, b int) int { 186 | return a ^ b 187 | } 188 | 189 | func fieldInv(a int) int { 190 | if a == 0 { 191 | panic("a == 0") 192 | } 193 | return fieldExpTable[256-fieldLogTable[a]-1] 194 | } 195 | 196 | func fieldMult(a, b int) int { 197 | if a == 0 || b == 0 { 198 | return 0 199 | } 200 | return fieldExpTable[(fieldLogTable[a]+fieldLogTable[b])%255] 201 | } 202 | 203 | func fieldBuildMonomial(degree, coefficient int) gfPoly { 204 | if degree < 0 { 205 | panic("degree < 0") 206 | } 207 | if coefficient == 0 { 208 | return fieldZero 209 | } 210 | coeff := make([]int, degree+1) 211 | coeff[0] = coefficient 212 | return newGFPoly(coeff) 213 | } 214 | 215 | type gfPoly struct { 216 | coefficients []int 217 | } 218 | 219 | func buildGenerator(degree int) gfPoly { 220 | for degree >= len(cachedGenerators) { 221 | d := len(cachedGenerators) - 1 222 | lastGenerator := cachedGenerators[d] 223 | cachedGenerators = append(cachedGenerators, lastGenerator.Multiply(newGFPoly([]int{1, fieldExpTable[d]}))) 224 | } 225 | return cachedGenerators[degree] 226 | } 227 | 228 | func newGFPoly(coefficients []int) gfPoly { 229 | if len(coefficients) == 0 { 230 | panic("len(coefficients) == 0") 231 | } 232 | for len(coefficients) > 0 { 233 | if coefficients[0] != 0 { 234 | return gfPoly{coefficients} 235 | } 236 | coefficients = coefficients[1:] 237 | } 238 | return fieldZero 239 | } 240 | 241 | func (p gfPoly) Degree() int { 242 | return len(p.coefficients) - 1 243 | } 244 | 245 | func (p gfPoly) IsZero() bool { 246 | return p.coefficients[0] == 0 247 | } 248 | 249 | func (p gfPoly) AddSub(x gfPoly) gfPoly { 250 | if p.IsZero() { 251 | return x 252 | } 253 | if x.IsZero() { 254 | return p 255 | } 256 | smallerCoeff := p.coefficients 257 | largerCoeff := x.coefficients 258 | if len(smallerCoeff) > len(largerCoeff) { 259 | smallerCoeff, largerCoeff = largerCoeff, smallerCoeff 260 | } 261 | coeff := make([]int, len(largerCoeff)) 262 | lenDiff := len(largerCoeff) - len(smallerCoeff) 263 | copy(coeff, largerCoeff[:lenDiff]) 264 | for i := lenDiff; i < len(coeff); i++ { 265 | coeff[i] = fieldAddSub(smallerCoeff[i-lenDiff], largerCoeff[i]) 266 | } 267 | return newGFPoly(coeff) 268 | } 269 | 270 | func (p gfPoly) Multiply(x gfPoly) gfPoly { 271 | if p.IsZero() || x.IsZero() { 272 | return fieldZero 273 | } 274 | coeff := make([]int, len(x.coefficients)+len(p.coefficients)-1) 275 | for i, a := range p.coefficients { 276 | for j, b := range x.coefficients { 277 | coeff[i+j] = fieldAddSub(coeff[i+j], fieldMult(a, b)) 278 | } 279 | } 280 | return newGFPoly(coeff) 281 | } 282 | 283 | func (p gfPoly) MultiplyByMonomial(degree, coefficient int) gfPoly { 284 | if degree < 0 { 285 | panic("degree < 0") 286 | } 287 | if coefficient == 0 { 288 | return fieldZero 289 | } 290 | coeff := make([]int, len(p.coefficients)+degree) 291 | for i, c := range p.coefficients { 292 | coeff[i] = fieldMult(c, coefficient) 293 | } 294 | return newGFPoly(coeff) 295 | } 296 | 297 | func (p gfPoly) Divide(x gfPoly) (gfPoly, gfPoly) { 298 | if x.IsZero() { 299 | panic("x.IsZero()") 300 | } 301 | quotient := fieldZero 302 | remainder := p 303 | 304 | inverseDenominatorLeadingTerm := fieldInv(x.coefficients[0]) 305 | 306 | for remainder.Degree() >= x.Degree() && !remainder.IsZero() { 307 | degreeDifference := remainder.Degree() - x.Degree() 308 | scale := fieldMult(remainder.coefficients[0], inverseDenominatorLeadingTerm) 309 | term := x.MultiplyByMonomial(degreeDifference, scale) 310 | iterationQuotient := fieldBuildMonomial(degreeDifference, scale) 311 | quotient = quotient.AddSub(iterationQuotient) 312 | remainder = remainder.AddSub(term) 313 | } 314 | return quotient, remainder 315 | } 316 | -------------------------------------------------------------------------------- /qrencode/int32bits.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | type uint32BitVector struct { 4 | bitIndex byte 5 | bits []uint32 6 | } 7 | 8 | func (v *uint32BitVector) Length() int { 9 | if v.bitIndex == 0 { 10 | return len(v.bits) * 32 11 | } 12 | return (len(v.bits)-1)*32 + int(v.bitIndex) 13 | } 14 | 15 | func (v *uint32BitVector) Get(i int) bool { 16 | return (v.bits[i/32]>>uint(i%32))&1 == 1 17 | } 18 | 19 | func (v *uint32BitVector) AppendBit(b bool) { 20 | if v.bitIndex == 0 { 21 | v.bits = append(v.bits, 0) 22 | } 23 | if b { 24 | v.bits[len(v.bits)-1] |= 1 << v.bitIndex 25 | } else { 26 | v.bits[len(v.bits)-1] &= 0xffffffff ^ (1 << v.bitIndex) 27 | } 28 | v.bitIndex++ 29 | v.bitIndex %= 32 30 | } 31 | 32 | func (v *uint32BitVector) Append(b, count int) { 33 | for i := uint(count); i > 0; i-- { 34 | v.AppendBit((b>>(i-1))&1 == 1) 35 | } 36 | } 37 | 38 | func (v *uint32BitVector) AppendBits(b uint32BitVector) { 39 | if v.bitIndex == 0 { 40 | v.bitIndex = b.bitIndex 41 | v.bits = append(v.bits, b.bits...) 42 | } else { 43 | for i, l := 0, b.Length(); i < l; i++ { 44 | v.AppendBit(b.Get(i)) 45 | } 46 | } 47 | } 48 | 49 | type uint32BitGrid struct { 50 | width, height int 51 | bits []uint32 52 | } 53 | 54 | func newUint32BitGrid(width, height int) uint32BitGrid { 55 | return uint32BitGrid{width, height, make([]uint32, (2*width*height+31)/32)} 56 | } 57 | 58 | func (g *uint32BitGrid) Width() int { 59 | return g.width 60 | } 61 | 62 | func (g *uint32BitGrid) Height() int { 63 | return g.height 64 | } 65 | 66 | func (g *uint32BitGrid) Empty(x, y int) bool { 67 | i := 2 * (x + y*g.width) 68 | return (g.bits[i/32]>>uint(i%32))&1 == 0 69 | } 70 | 71 | func (g *uint32BitGrid) Get(x, y int) bool { 72 | i := 2*(x+y*g.width) + 1 73 | return (g.bits[i/32]>>uint(i%32))&1 == 0 74 | } 75 | 76 | func (g *uint32BitGrid) Set(x, y int, v bool) { 77 | i := 2 * (x + y*g.width) 78 | if v { 79 | g.bits[i/32] |= 3 << uint(i%32) 80 | } else { 81 | g.bits[i/32] |= 1 << uint(i%32) 82 | g.bits[i/32] &= 0xffffffff ^ (1 << uint(i%32+1)) 83 | } 84 | } 85 | 86 | func (g *uint32BitGrid) Clear() { 87 | for i, _ := range g.bits { 88 | g.bits[i] = 0 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /qrencode/mode.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | const ( 4 | modeTerminator = modeIndicator(0) 5 | modeNumeric = modeIndicator(1) 6 | modeAlphanumeric = modeIndicator(2) 7 | modeStructuredAppend = modeIndicator(3) 8 | modeByte = modeIndicator(4) 9 | modeFNC1FirstPosition = modeIndicator(5) 10 | modeECI = modeIndicator(7) 11 | modeKanji = modeIndicator(8) 12 | modeFNC1SecondPosition = modeIndicator(9) 13 | ) 14 | 15 | type modeIndicator int 16 | 17 | func getMode(content string) modeIndicator { 18 | numeric := false 19 | alphanumeric := false 20 | for _, b := range []byte(content) { 21 | if code, err := alphanumericCode(b); err != nil { 22 | return modeByte 23 | } else if code < 10 { 24 | numeric = true 25 | } else { 26 | alphanumeric = true 27 | } 28 | } 29 | if alphanumeric { 30 | return modeAlphanumeric 31 | } 32 | if numeric { 33 | return modeNumeric 34 | } 35 | return modeByte 36 | } 37 | 38 | func (m modeIndicator) characterCountBits(v versionNumber) int { 39 | switch { 40 | case v < 1: 41 | panic("Invalid versionNumber") 42 | case v <= 9: 43 | switch m { 44 | case modeNumeric: 45 | return 10 46 | case modeAlphanumeric: 47 | return 9 48 | case modeByte: 49 | return 8 50 | case modeKanji: 51 | return 8 52 | default: 53 | panic("Unsupported mode") 54 | } 55 | case v <= 26: 56 | switch m { 57 | case modeNumeric: 58 | return 12 59 | case modeAlphanumeric: 60 | return 11 61 | case modeByte: 62 | return 16 63 | case modeKanji: 64 | return 10 65 | default: 66 | panic("Unsupported mode") 67 | } 68 | case v <= 40: 69 | switch m { 70 | case modeNumeric: 71 | return 14 72 | case modeAlphanumeric: 73 | return 13 74 | case modeByte: 75 | return 16 76 | case modeKanji: 77 | return 12 78 | default: 79 | panic("Unsupported mode") 80 | } 81 | } 82 | panic("Invalid versionNumber") 83 | } 84 | -------------------------------------------------------------------------------- /qrencode/qr_test.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | import ( 4 | "image/png" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | func TestContentBits(t *testing.T) { 10 | bits, version, err := stringContentBits("HELLO WORLD", ECLevelQ) 11 | if err != nil { 12 | t.Error(err.Error()) 13 | } 14 | if version != versionNumber(1) { 15 | t.Error("version", version, " != 1") 16 | } 17 | if bits.String() != "00100000010110110000101101111000110100010111001011011100010011010100001101000000111011000001000111101100" { 18 | t.Error("bits", bits.String(), " != 00100000010110110000101101111000110100010111001011011100010011010100001101000000111011000001000111101100") 19 | } 20 | bits = interleaveWithECBytes(bits, version, ECLevelQ) 21 | if bits.String() != "0010000001011011000010110111100011010001011100101101110001001101010000110100000011101100000100011110110010101000010010000001011001010010110110010011011010011100000000000010111000001111101101000111101000010000" { 22 | t.Error("bits", bits.String(), " != 0010000001011011000010110111100011010001011100101101110001001101010000110100000011101100000100011110110010101000010010000001011001010010110110010011011010011100000000000010111000001111101101000111101000010000") 23 | } 24 | } 25 | 26 | func TestGenerateECBytes(t *testing.T) { 27 | block := blockPair{ 28 | dataBytes: []int{32, 91, 11, 120, 209, 114, 220, 77, 67, 64, 236, 17, 236}, 29 | ecBytes: make([]int, 13), 30 | } 31 | generateECBytes(&block) 32 | for i, b := range []int{32, 91, 11, 120, 209, 114, 220, 77, 67, 64, 236, 17, 236} { 33 | if block.dataBytes[i] != b { 34 | t.Error("dataBytes", i, block.dataBytes[i], b) 35 | } 36 | } 37 | for i, b := range []int{168, 72, 22, 82, 217, 54, 156, 0, 46, 15, 180, 122, 16} { 38 | if block.ecBytes[i] != b { 39 | t.Error("ecBytes", i, block.ecBytes[i], b) 40 | } 41 | } 42 | } 43 | 44 | func BenchmarkEncode(b *testing.B) { 45 | for i := 0; i < b.N; i++ { 46 | Encode("Testing one two three four five six seven eight nine ten eleven twelve thirteen", ECLevelQ) 47 | } 48 | } 49 | 50 | func ExampleEncode() { 51 | grid, err := Encode("Testing one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty.", ECLevelQ) 52 | if err != nil { 53 | return 54 | } 55 | f, err := os.Create("/tmp/qr.png") 56 | if err != nil { 57 | return 58 | } 59 | defer f.Close() 60 | png.Encode(f, grid.Image(8)) 61 | } 62 | -------------------------------------------------------------------------------- /qrencode/qrgrid.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | var ( 4 | positionDetectionPatternBack = [][]byte{ 5 | {0, 0, 0, 0, 0, 0, 0, 0}, 6 | {0, 0, 0, 0, 0, 0, 0, 0}, 7 | {0, 0, 0, 0, 0, 0, 0, 0}, 8 | {0, 0, 0, 0, 0, 0, 0, 0}, 9 | {0, 0, 0, 0, 0, 0, 0, 0}, 10 | {0, 0, 0, 0, 0, 0, 0, 0}, 11 | {0, 0, 0, 0, 0, 0, 0, 0}, 12 | {0, 0, 0, 0, 0, 0, 0, 0}, 13 | } 14 | 15 | positionDetectionPattern = [][]byte{ 16 | {1, 1, 1, 1, 1, 1, 1}, 17 | {1, 0, 0, 0, 0, 0, 1}, 18 | {1, 0, 1, 1, 1, 0, 1}, 19 | {1, 0, 1, 1, 1, 0, 1}, 20 | {1, 0, 1, 1, 1, 0, 1}, 21 | {1, 0, 0, 0, 0, 0, 1}, 22 | {1, 1, 1, 1, 1, 1, 1}, 23 | } 24 | 25 | positionAdjustmentPattern = [][]byte{ 26 | {1, 1, 1, 1, 1}, 27 | {1, 0, 0, 0, 1}, 28 | {1, 0, 1, 0, 1}, 29 | {1, 0, 0, 0, 1}, 30 | {1, 1, 1, 1, 1}, 31 | } 32 | 33 | positionAdjustmentPatternCoordinateTable = [][]int{ 34 | {}, 35 | {}, // Version 1 36 | {6, 18}, // Version 2 37 | {6, 22}, // Version 3 38 | {6, 26}, // Version 4 39 | {6, 30}, // Version 5 40 | {6, 34}, // Version 6 41 | {6, 22, 38}, // Version 7 42 | {6, 24, 42}, // Version 8 43 | {6, 26, 46}, // Version 9 44 | {6, 28, 50}, // Version 10 45 | {6, 30, 54}, // Version 11 46 | {6, 32, 58}, // Version 12 47 | {6, 34, 62}, // Version 13 48 | {6, 26, 46, 66}, // Version 14 49 | {6, 26, 48, 70}, // Version 15 50 | {6, 26, 50, 74}, // Version 16 51 | {6, 30, 54, 78}, // Version 17 52 | {6, 30, 56, 82}, // Version 18 53 | {6, 30, 58, 86}, // Version 19 54 | {6, 34, 62, 90}, // Version 20 55 | {6, 28, 50, 72, 94}, // Version 21 56 | {6, 26, 50, 74, 98}, // Version 22 57 | {6, 30, 54, 78, 102}, // Version 23 58 | {6, 28, 54, 80, 106}, // Version 24 59 | {6, 32, 58, 84, 110}, // Version 25 60 | {6, 30, 58, 86, 114}, // Version 26 61 | {6, 34, 62, 90, 118}, // Version 27 62 | {6, 26, 50, 74, 98, 122}, // Version 28 63 | {6, 30, 54, 78, 102, 126}, // Version 29 64 | {6, 26, 52, 78, 104, 130}, // Version 30 65 | {6, 30, 56, 82, 108, 134}, // Version 31 66 | {6, 34, 60, 86, 112, 138}, // Version 32 67 | {6, 30, 58, 86, 114, 142}, // Version 33 68 | {6, 34, 62, 90, 118, 146}, // Version 34 69 | {6, 30, 54, 78, 102, 126, 150}, // Version 35 70 | {6, 24, 50, 76, 102, 128, 154}, // Version 36 71 | {6, 28, 54, 80, 106, 132, 158}, // Version 37 72 | {6, 32, 58, 84, 110, 136, 162}, // Version 38 73 | {6, 26, 54, 82, 110, 138, 166}, // Version 39 74 | {6, 30, 58, 86, 114, 142, 170}, // Version 40 75 | } 76 | 77 | typeInfoCoordinates = [][]int{ 78 | {8, 0}, 79 | {8, 1}, 80 | {8, 2}, 81 | {8, 3}, 82 | {8, 4}, 83 | {8, 5}, 84 | {8, 7}, 85 | {8, 8}, 86 | {7, 8}, 87 | {5, 8}, 88 | {4, 8}, 89 | {3, 8}, 90 | {2, 8}, 91 | {1, 8}, 92 | {0, 8}, 93 | } 94 | ) 95 | 96 | const ( 97 | versionInfoPoly = 0x1f25 98 | typeInfoPoly = 0x537 99 | typeInfoMaskPattern = 0x5412 100 | ) 101 | 102 | func bestMaskPattern(bits *BitVector, version versionNumber, ecLevel ECLevel, grid *BitGrid) int { 103 | bestMaskPattern := -1 104 | bestPenalty := 0 105 | for maskPattern := 0; maskPattern < 8; maskPattern++ { 106 | buildGrid(bits, version, ecLevel, maskPattern, grid) 107 | penalty := maskPenalty(grid) 108 | if bestMaskPattern < 0 || penalty < bestPenalty { 109 | bestMaskPattern = maskPattern 110 | bestPenalty = penalty 111 | } 112 | } 113 | if bestMaskPattern < 0 { 114 | panic("bestMaskPattern < 0") 115 | } 116 | return bestMaskPattern 117 | } 118 | 119 | func buildGrid(bits *BitVector, version versionNumber, ecLevel ECLevel, maskPattern int, grid *BitGrid) { 120 | grid.Clear() 121 | embedBasicPatterns(version, grid) 122 | embedTypeInfo(ecLevel, maskPattern, grid) 123 | maybeEmbedVersionInfo(version, grid) 124 | embedDataBits(bits, maskPattern, grid) 125 | } 126 | 127 | func embedBasicPatterns(version versionNumber, grid *BitGrid) { 128 | embedPositionDetectionPatternsAndSeparators(grid) 129 | embedDarkDotAtLeftBottomCorner(grid) 130 | maybeEmbedPositionAdjustmentPatterns(version, grid) 131 | embedTimingPatterns(grid) 132 | } 133 | 134 | func embedPositionDetectionPatternsAndSeparators(grid *BitGrid) { 135 | embedPattern(0, 0, positionDetectionPatternBack, grid) 136 | embedPattern(grid.Width()-len(positionDetectionPatternBack[0]), 0, positionDetectionPatternBack, grid) 137 | embedPattern(0, grid.Height()-len(positionDetectionPatternBack), positionDetectionPatternBack, grid) 138 | embedPattern(0, 0, positionDetectionPattern, grid) 139 | embedPattern(grid.Width()-len(positionDetectionPattern[0]), 0, positionDetectionPattern, grid) 140 | embedPattern(0, grid.Height()-len(positionDetectionPattern), positionDetectionPattern, grid) 141 | } 142 | 143 | func embedDarkDotAtLeftBottomCorner(grid *BitGrid) { 144 | grid.Set(8, grid.Height()-8, true) 145 | } 146 | 147 | func maybeEmbedPositionAdjustmentPatterns(version versionNumber, grid *BitGrid) { 148 | h := len(positionAdjustmentPattern) 149 | w := len(positionAdjustmentPattern[h/2]) 150 | for _, y := range positionAdjustmentPatternCoordinateTable[version] { 151 | for _, x := range positionAdjustmentPatternCoordinateTable[version] { 152 | if grid.Empty(x, y) { 153 | embedPattern(x-w/2, y-h/2, positionAdjustmentPattern, grid) 154 | } 155 | } 156 | } 157 | } 158 | 159 | func embedPattern(x0, y0 int, pattern [][]byte, grid *BitGrid) { 160 | for y, row := range pattern { 161 | for x, v := range row { 162 | grid.Set(x0+x, y0+y, v != 0) 163 | } 164 | } 165 | } 166 | 167 | func embedTimingPatterns(grid *BitGrid) { 168 | for i := 0; i < grid.Width(); i++ { 169 | if grid.Empty(i, 6) { 170 | grid.Set(i, 6, i&1 == 0) 171 | } 172 | } 173 | for i := 0; i < grid.Height(); i++ { 174 | if grid.Empty(6, i) { 175 | grid.Set(6, i, i&1 == 0) 176 | } 177 | } 178 | } 179 | 180 | func embedTypeInfo(ecLevel ECLevel, maskPattern int, grid *BitGrid) { 181 | typeInfo := int(ecLevel)<<3 | maskPattern 182 | bchCode := calculateBCHCode(typeInfo, typeInfoPoly) 183 | typeInfo = (typeInfo<<10 | (bchCode & 0x3ff)) ^ typeInfoMaskPattern 184 | for i := 0; i < 15; i++ { 185 | bit := (typeInfo>>uint(i))&1 == 1 186 | grid.Set(typeInfoCoordinates[i][0], typeInfoCoordinates[i][1], bit) 187 | if i < 8 { 188 | grid.Set(grid.Width()-i-1, 8, bit) 189 | } else { 190 | grid.Set(8, grid.Height()+i-15, bit) 191 | } 192 | } 193 | } 194 | 195 | func maybeEmbedVersionInfo(version versionNumber, grid *BitGrid) { 196 | if version < 7 { 197 | return 198 | } 199 | versionInfo := int(version)<<12 | calculateBCHCode(int(version), versionInfoPoly) 200 | for i := 0; i < 6; i++ { 201 | for j := 0; j < 3; j++ { 202 | bit := versionInfo&1 == 1 203 | versionInfo >>= 1 204 | grid.Set(i, grid.Height()-11+j, bit) 205 | grid.Set(grid.Width()-11+j, i, bit) 206 | } 207 | } 208 | } 209 | 210 | func embedDataBits(bits *BitVector, maskPattern int, grid *BitGrid) { 211 | bitIndex := 0 212 | for direction, x, y := -1, grid.Width()-1, grid.Height()-1; x > 0; x, y, direction = x-2, y-direction, -direction { 213 | if x == 6 { 214 | x-- 215 | } 216 | for ; y >= 0 && y < grid.Height(); y += direction { 217 | for i := 0; i < 2; i++ { 218 | xx := x - i 219 | if !grid.Empty(xx, y) { 220 | continue 221 | } 222 | bit := false 223 | if bitIndex < bits.Length() { 224 | bit = bits.Get(bitIndex) 225 | bitIndex++ 226 | } 227 | if mask(maskPattern, xx, y) { 228 | bit = !bit 229 | } 230 | grid.Set(xx, y, bit) 231 | } 232 | } 233 | } 234 | if bitIndex != bits.Length() { 235 | panic("bitIndex != bits.Length()") 236 | } 237 | } 238 | 239 | func calculateBCHCode(value, poly int) int { 240 | msbSetInPoly := findMSBSet(poly) 241 | value <<= uint(msbSetInPoly - 1) 242 | for findMSBSet(value) >= msbSetInPoly { 243 | value ^= poly << uint(findMSBSet(value)-msbSetInPoly) 244 | } 245 | return value 246 | } 247 | 248 | func findMSBSet(value int) int { 249 | numDigits := 0 250 | for v := uint(value); v != 0; v >>= 1 { 251 | numDigits++ 252 | } 253 | return numDigits 254 | } 255 | 256 | func mask(maskPattern int, x, y int) bool { 257 | switch maskPattern { 258 | case 0: 259 | return (x+y)&1 == 0 260 | case 1: 261 | return y&1 == 0 262 | case 2: 263 | return x%3 == 0 264 | case 3: 265 | return (x+y)%3 == 0 266 | case 4: 267 | return (x/3+y>>1)&1 == 0 268 | case 5: 269 | return (x*y)&1+(x*y)%3 == 0 270 | case 6: 271 | return ((x*y)&1+(x*y)%3)&1 == 0 272 | case 7: 273 | return ((x*y)%3+(x+y)&1)&1 == 0 274 | } 275 | return false 276 | } 277 | 278 | func maskPenalty(grid *BitGrid) int { 279 | return maskPenaltyRule1(grid) + maskPenaltyRule2(grid) + maskPenaltyRule3(grid) + maskPenaltyRule4(grid) 280 | } 281 | 282 | func maskPenaltyRule1(grid *BitGrid) int { 283 | penalty := 0 284 | for x := 0; x < grid.Width(); x++ { 285 | for y, count := 1, 1; y < grid.Height(); y++ { 286 | if grid.Get(x, y) == grid.Get(x, y-1) { 287 | count++ 288 | if count == 5 { 289 | penalty += 3 290 | } else if count > 5 { 291 | penalty++ 292 | } 293 | } else { 294 | count = 1 295 | } 296 | } 297 | } 298 | for y := 0; y < grid.Height(); y++ { 299 | for x, count := 1, 1; x < grid.Width(); x++ { 300 | if grid.Get(x, y) == grid.Get(x-1, y) { 301 | count++ 302 | if count == 5 { 303 | penalty += 3 304 | } else if count > 5 { 305 | penalty++ 306 | } 307 | } else { 308 | count = 1 309 | } 310 | } 311 | } 312 | return penalty 313 | } 314 | 315 | func maskPenaltyRule2(grid *BitGrid) int { 316 | penalty := 0 317 | for y := 1; y < grid.Height(); y++ { 318 | for x := 1; x < grid.Width(); x++ { 319 | v := grid.Get(x, y) 320 | if v == grid.Get(x-1, y) && v == grid.Get(x-1, y-1) && v == grid.Get(x, y-1) { 321 | penalty += 3 322 | } 323 | } 324 | } 325 | return penalty 326 | } 327 | 328 | func maskPenaltyRule3(grid *BitGrid) int { 329 | penalty := 0 330 | for y := 0; y < grid.Height(); y++ { 331 | for x := 0; x < grid.Width(); x++ { 332 | if x+6 < grid.Width() && 333 | grid.Get(x, y) && 334 | !grid.Get(x+1, y) && 335 | grid.Get(x+2, y) && 336 | grid.Get(x+3, y) && 337 | grid.Get(x+4, y) && 338 | !grid.Get(x+5, y) && 339 | grid.Get(x+6, y) { 340 | if x+10 < grid.Width() && 341 | !grid.Get(x+7, y) && 342 | !grid.Get(x+8, y) && 343 | !grid.Get(x+9, y) && 344 | !grid.Get(x+10, y) { 345 | penalty += 40 346 | } 347 | if x-4 >= 0 && 348 | !grid.Get(x-4, y) && 349 | !grid.Get(x-3, y) && 350 | !grid.Get(x-2, y) && 351 | !grid.Get(x-1, y) { 352 | penalty += 40 353 | } 354 | } 355 | if y+6 < grid.Height() && 356 | grid.Get(x, y) && 357 | !grid.Get(x, y+1) && 358 | grid.Get(x, y+2) && 359 | grid.Get(x, y+3) && 360 | grid.Get(x, y+4) && 361 | !grid.Get(x, y+5) && 362 | grid.Get(x, y+6) { 363 | if y+10 < grid.Height() && 364 | !grid.Get(x, y+7) && 365 | !grid.Get(x, y+8) && 366 | !grid.Get(x, y+9) && 367 | !grid.Get(x, y+10) { 368 | penalty += 40 369 | } 370 | if y-4 >= 0 && 371 | !grid.Get(x, y-4) && 372 | !grid.Get(x, y-3) && 373 | !grid.Get(x, y-2) && 374 | !grid.Get(x, y-1) { 375 | penalty += 40 376 | } 377 | } 378 | } 379 | } 380 | return penalty 381 | } 382 | 383 | func maskPenaltyRule4(grid *BitGrid) int { 384 | total := grid.Width() * grid.Height() 385 | dark := -total / 2 386 | for y := 0; y < grid.Height(); y++ { 387 | for x := 0; x < grid.Width(); x++ { 388 | if grid.Get(x, y) { 389 | dark++ 390 | } 391 | } 392 | } 393 | if dark < 0 { 394 | dark = 1 - dark 395 | } 396 | return (dark * 200) / total 397 | } 398 | -------------------------------------------------------------------------------- /qrencode/version.go: -------------------------------------------------------------------------------- 1 | package qrencode 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | type versionNumber int 8 | 9 | type ecbs struct { 10 | codewordsPerBlock int 11 | blocks []ecb 12 | } 13 | 14 | type ecb struct { 15 | count, dataCodewords int 16 | } 17 | 18 | func (blocks ecbs) numBlocks() int { 19 | total := 0 20 | for _, block := range blocks.blocks { 21 | total += block.count 22 | } 23 | return total 24 | } 25 | 26 | func (blocks ecbs) totalECCodewords() int { 27 | return blocks.numBlocks() * blocks.codewordsPerBlock 28 | } 29 | 30 | var ( 31 | ecBlocks = [41][4]ecbs{ 32 | [4]ecbs{}, 33 | [4]ecbs{ // 1 34 | ecbs{10, []ecb{ecb{1, 16}}}, // M 35 | ecbs{7, []ecb{ecb{1, 19}}}, // L 36 | ecbs{17, []ecb{ecb{1, 9}}}, // H 37 | ecbs{13, []ecb{ecb{1, 13}}}, // Q 38 | }, 39 | [4]ecbs{ // 2 40 | ecbs{16, []ecb{ecb{1, 28}}}, // M 41 | ecbs{10, []ecb{ecb{1, 34}}}, // L 42 | ecbs{28, []ecb{ecb{1, 16}}}, // H 43 | ecbs{22, []ecb{ecb{1, 22}}}, // Q 44 | }, 45 | [4]ecbs{ // 3 46 | ecbs{26, []ecb{ecb{1, 44}}}, // M 47 | ecbs{15, []ecb{ecb{1, 55}}}, // L 48 | ecbs{22, []ecb{ecb{2, 13}}}, // H 49 | ecbs{18, []ecb{ecb{2, 17}}}, // Q 50 | }, 51 | [4]ecbs{ // 4 52 | ecbs{18, []ecb{ecb{2, 32}}}, // M 53 | ecbs{20, []ecb{ecb{1, 80}}}, // L 54 | ecbs{16, []ecb{ecb{4, 9}}}, // H 55 | ecbs{26, []ecb{ecb{2, 24}}}, // Q 56 | }, 57 | [4]ecbs{ // 5 58 | ecbs{24, []ecb{ecb{2, 43}}}, // M 59 | ecbs{26, []ecb{ecb{1, 108}}}, // L 60 | ecbs{22, []ecb{ecb{2, 11}, ecb{2, 12}}}, // H 61 | ecbs{18, []ecb{ecb{2, 15}, ecb{2, 16}}}, // Q 62 | }, 63 | [4]ecbs{ // 6 64 | ecbs{16, []ecb{ecb{4, 27}}}, // M 65 | ecbs{18, []ecb{ecb{2, 68}}}, // L 66 | ecbs{28, []ecb{ecb{4, 15}}}, // H 67 | ecbs{24, []ecb{ecb{4, 19}}}, // Q 68 | }, 69 | [4]ecbs{ // 7 70 | ecbs{18, []ecb{ecb{4, 31}}}, // M 71 | ecbs{20, []ecb{ecb{2, 78}}}, // L 72 | ecbs{26, []ecb{ecb{4, 13}, ecb{1, 14}}}, // H 73 | ecbs{18, []ecb{ecb{2, 14}, ecb{4, 15}}}, // Q 74 | }, 75 | [4]ecbs{ // 8 76 | ecbs{22, []ecb{ecb{2, 38}, ecb{2, 39}}}, // M 77 | ecbs{24, []ecb{ecb{2, 97}}}, // L 78 | ecbs{26, []ecb{ecb{4, 14}, ecb{2, 15}}}, // H 79 | ecbs{22, []ecb{ecb{4, 18}, ecb{2, 19}}}, // Q 80 | }, 81 | [4]ecbs{ // 9 82 | ecbs{22, []ecb{ecb{3, 36}, ecb{2, 37}}}, // M 83 | ecbs{30, []ecb{ecb{2, 116}}}, // L 84 | ecbs{24, []ecb{ecb{4, 12}, ecb{4, 13}}}, // H 85 | ecbs{20, []ecb{ecb{4, 16}, ecb{4, 17}}}, // Q 86 | }, 87 | [4]ecbs{ // 10 88 | ecbs{26, []ecb{ecb{4, 43}, ecb{1, 44}}}, // M 89 | ecbs{18, []ecb{ecb{2, 68}, ecb{2, 69}}}, // L 90 | ecbs{28, []ecb{ecb{6, 15}, ecb{2, 16}}}, // H 91 | ecbs{24, []ecb{ecb{6, 19}, ecb{2, 20}}}, // Q 92 | }, 93 | [4]ecbs{ // 11 94 | ecbs{30, []ecb{ecb{1, 50}, ecb{4, 51}}}, // M 95 | ecbs{20, []ecb{ecb{4, 81}}}, // L 96 | ecbs{24, []ecb{ecb{3, 12}, ecb{8, 13}}}, // H 97 | ecbs{28, []ecb{ecb{4, 22}, ecb{4, 23}}}, // Q 98 | }, 99 | [4]ecbs{ // 12 100 | ecbs{22, []ecb{ecb{6, 36}, ecb{2, 37}}}, // M 101 | ecbs{24, []ecb{ecb{2, 92}, ecb{2, 93}}}, // L 102 | ecbs{28, []ecb{ecb{7, 14}, ecb{4, 15}}}, // H 103 | ecbs{26, []ecb{ecb{4, 20}, ecb{6, 21}}}, // Q 104 | }, 105 | [4]ecbs{ // 13 106 | ecbs{22, []ecb{ecb{8, 37}, ecb{1, 38}}}, // M 107 | ecbs{26, []ecb{ecb{4, 107}}}, // L 108 | ecbs{22, []ecb{ecb{12, 11}, ecb{4, 12}}}, // H 109 | ecbs{24, []ecb{ecb{8, 20}, ecb{4, 21}}}, // Q 110 | }, 111 | [4]ecbs{ // 14 112 | ecbs{24, []ecb{ecb{4, 40}, ecb{5, 41}}}, // M 113 | ecbs{30, []ecb{ecb{3, 115}, ecb{1, 116}}}, // L 114 | ecbs{24, []ecb{ecb{11, 12}, ecb{5, 13}}}, // H 115 | ecbs{20, []ecb{ecb{11, 16}, ecb{5, 17}}}, // Q 116 | }, 117 | [4]ecbs{ // 15 118 | ecbs{24, []ecb{ecb{5, 41}, ecb{5, 42}}}, // M 119 | ecbs{22, []ecb{ecb{5, 87}, ecb{1, 88}}}, // L 120 | ecbs{24, []ecb{ecb{11, 12}, ecb{7, 13}}}, // H 121 | ecbs{30, []ecb{ecb{5, 24}, ecb{7, 25}}}, // Q 122 | }, 123 | [4]ecbs{ // 16 124 | ecbs{28, []ecb{ecb{7, 45}, ecb{3, 46}}}, // M 125 | ecbs{24, []ecb{ecb{5, 98}, ecb{1, 99}}}, // L 126 | ecbs{30, []ecb{ecb{3, 15}, ecb{13, 16}}}, // H 127 | ecbs{24, []ecb{ecb{15, 19}, ecb{2, 20}}}, // Q 128 | }, 129 | [4]ecbs{ // 17 130 | ecbs{28, []ecb{ecb{10, 46}, ecb{1, 47}}}, // M 131 | ecbs{28, []ecb{ecb{1, 107}, ecb{5, 108}}}, // L 132 | ecbs{28, []ecb{ecb{2, 14}, ecb{17, 15}}}, // H 133 | ecbs{28, []ecb{ecb{1, 22}, ecb{15, 23}}}, // Q 134 | }, 135 | [4]ecbs{ // 18 136 | ecbs{26, []ecb{ecb{9, 43}, ecb{4, 44}}}, // M 137 | ecbs{30, []ecb{ecb{5, 120}, ecb{1, 121}}}, // L 138 | ecbs{28, []ecb{ecb{2, 14}, ecb{19, 15}}}, // H 139 | ecbs{28, []ecb{ecb{17, 22}, ecb{1, 23}}}, // Q 140 | }, 141 | [4]ecbs{ // 19 142 | ecbs{26, []ecb{ecb{3, 44}, ecb{11, 44}}}, // M 143 | ecbs{28, []ecb{ecb{3, 113}, ecb{4, 114}}}, // L 144 | ecbs{26, []ecb{ecb{9, 13}, ecb{16, 14}}}, // H 145 | ecbs{26, []ecb{ecb{17, 21}, ecb{4, 22}}}, // Q 146 | }, 147 | [4]ecbs{ // 20 148 | ecbs{26, []ecb{ecb{3, 41}, ecb{13, 42}}}, // M 149 | ecbs{28, []ecb{ecb{3, 107}, ecb{5, 108}}}, // L 150 | ecbs{28, []ecb{ecb{15, 15}, ecb{10, 16}}}, // H 151 | ecbs{30, []ecb{ecb{15, 24}, ecb{5, 25}}}, // Q 152 | }, 153 | [4]ecbs{ // 21 154 | ecbs{26, []ecb{ecb{17, 42}}}, // M 155 | ecbs{28, []ecb{ecb{4, 116}, ecb{4, 117}}}, // L 156 | ecbs{30, []ecb{ecb{19, 16}, ecb{6, 17}}}, // H 157 | ecbs{28, []ecb{ecb{17, 22}, ecb{6, 23}}}, // Q 158 | }, 159 | [4]ecbs{ // 22 160 | ecbs{28, []ecb{ecb{17, 46}}}, // M 161 | ecbs{28, []ecb{ecb{2, 111}, ecb{7, 112}}}, // L 162 | ecbs{24, []ecb{ecb{34, 13}}}, // H 163 | ecbs{30, []ecb{ecb{7, 24}, ecb{16, 25}}}, // Q 164 | }, 165 | [4]ecbs{ // 23 166 | ecbs{28, []ecb{ecb{4, 47}, ecb{14, 48}}}, // M 167 | ecbs{30, []ecb{ecb{4, 121}, ecb{5, 122}}}, // L 168 | ecbs{30, []ecb{ecb{16, 15}, ecb{14, 16}}}, // H 169 | ecbs{30, []ecb{ecb{11, 24}, ecb{14, 25}}}, // Q 170 | }, 171 | [4]ecbs{ // 24 172 | ecbs{28, []ecb{ecb{6, 45}, ecb{14, 46}}}, // M 173 | ecbs{30, []ecb{ecb{6, 117}, ecb{4, 118}}}, // L 174 | ecbs{30, []ecb{ecb{30, 16}, ecb{2, 17}}}, // H 175 | ecbs{30, []ecb{ecb{11, 24}, ecb{16, 25}}}, // Q 176 | }, 177 | [4]ecbs{ // 25 178 | ecbs{28, []ecb{ecb{8, 47}, ecb{13, 48}}}, // M 179 | ecbs{26, []ecb{ecb{8, 106}, ecb{4, 107}}}, // L 180 | ecbs{30, []ecb{ecb{22, 15}, ecb{13, 16}}}, // H 181 | ecbs{30, []ecb{ecb{7, 24}, ecb{22, 25}}}, // Q 182 | }, 183 | [4]ecbs{ // 26 184 | ecbs{28, []ecb{ecb{19, 46}, ecb{4, 47}}}, // M 185 | ecbs{28, []ecb{ecb{10, 114}, ecb{2, 115}}}, // L 186 | ecbs{30, []ecb{ecb{33, 16}, ecb{4, 17}}}, // H 187 | ecbs{28, []ecb{ecb{28, 22}, ecb{6, 23}}}, // Q 188 | }, 189 | [4]ecbs{ // 27 190 | ecbs{28, []ecb{ecb{22, 45}, ecb{3, 46}}}, // M 191 | ecbs{30, []ecb{ecb{8, 122}, ecb{4, 123}}}, // L 192 | ecbs{30, []ecb{ecb{12, 15}, ecb{28, 16}}}, // H 193 | ecbs{30, []ecb{ecb{8, 23}, ecb{26, 24}}}, // Q 194 | }, 195 | [4]ecbs{ // 28 196 | ecbs{28, []ecb{ecb{3, 45}, ecb{23, 46}}}, // M 197 | ecbs{30, []ecb{ecb{3, 117}, ecb{10, 118}}}, // L 198 | ecbs{30, []ecb{ecb{11, 15}, ecb{31, 16}}}, // H 199 | ecbs{30, []ecb{ecb{4, 24}, ecb{31, 25}}}, // Q 200 | }, 201 | [4]ecbs{ // 29 202 | ecbs{28, []ecb{ecb{21, 45}, ecb{7, 46}}}, // M 203 | ecbs{30, []ecb{ecb{7, 116}, ecb{7, 117}}}, // L 204 | ecbs{30, []ecb{ecb{19, 15}, ecb{26, 16}}}, // H 205 | ecbs{30, []ecb{ecb{1, 32}, ecb{37, 24}}}, // Q 206 | }, 207 | [4]ecbs{ // 30 208 | ecbs{28, []ecb{ecb{19, 47}, ecb{10, 48}}}, // M 209 | ecbs{30, []ecb{ecb{5, 115}, ecb{10, 116}}}, // L 210 | ecbs{30, []ecb{ecb{23, 15}, ecb{25, 16}}}, // H 211 | ecbs{30, []ecb{ecb{15, 24}, ecb{25, 25}}}, // Q 212 | }, 213 | [4]ecbs{ // 31 214 | ecbs{28, []ecb{ecb{2, 46}, ecb{29, 47}}}, // M 215 | ecbs{30, []ecb{ecb{13, 115}, ecb{3, 116}}}, // L 216 | ecbs{30, []ecb{ecb{23, 15}, ecb{28, 16}}}, // H 217 | ecbs{30, []ecb{ecb{42, 24}, ecb{1, 25}}}, // Q 218 | }, 219 | [4]ecbs{ // 32 220 | ecbs{28, []ecb{ecb{10, 46}, ecb{23, 47}}}, // M 221 | ecbs{30, []ecb{ecb{17, 115}}}, // L 222 | ecbs{30, []ecb{ecb{19, 15}, ecb{35, 16}}}, // H 223 | ecbs{30, []ecb{ecb{10, 24}, ecb{35, 25}}}, // Q 224 | }, 225 | [4]ecbs{ // 33 226 | ecbs{28, []ecb{ecb{14, 46}, ecb{21, 47}}}, // M 227 | ecbs{30, []ecb{ecb{17, 115}, ecb{1, 116}}}, // L 228 | ecbs{30, []ecb{ecb{11, 15}, ecb{46, 16}}}, // H 229 | ecbs{30, []ecb{ecb{29, 24}, ecb{19, 25}}}, // Q 230 | }, 231 | [4]ecbs{ // 34 232 | ecbs{28, []ecb{ecb{14, 16}, ecb{23, 47}}}, // M 233 | ecbs{30, []ecb{ecb{13, 115}, ecb{6, 116}}}, // L 234 | ecbs{30, []ecb{ecb{59, 16}, ecb{1, 17}}}, // H 235 | ecbs{30, []ecb{ecb{44, 24}, ecb{7, 25}}}, // Q 236 | }, 237 | [4]ecbs{ // 35 238 | ecbs{28, []ecb{ecb{12, 47}, ecb{26, 48}}}, // M 239 | ecbs{30, []ecb{ecb{12, 121}, ecb{7, 122}}}, // L 240 | ecbs{30, []ecb{ecb{22, 15}, ecb{41, 16}}}, // H 241 | ecbs{30, []ecb{ecb{39, 24}, ecb{14, 25}}}, // Q 242 | }, 243 | [4]ecbs{ // 36 244 | ecbs{28, []ecb{ecb{6, 47}, ecb{34, 48}}}, // M 245 | ecbs{30, []ecb{ecb{6, 121}, ecb{14, 122}}}, // L 246 | ecbs{30, []ecb{ecb{2, 15}, ecb{64, 16}}}, // H 247 | ecbs{30, []ecb{ecb{46, 24}, ecb{10, 25}}}, // Q 248 | }, 249 | [4]ecbs{ // 37 250 | ecbs{28, []ecb{ecb{29, 46}, ecb{14, 47}}}, // M 251 | ecbs{30, []ecb{ecb{17, 122}, ecb{4, 123}}}, // L 252 | ecbs{30, []ecb{ecb{24, 15}, ecb{46, 16}}}, // H 253 | ecbs{30, []ecb{ecb{49, 24}, ecb{10, 25}}}, // Q 254 | }, 255 | [4]ecbs{ // 38 256 | ecbs{28, []ecb{ecb{13, 46}, ecb{32, 47}}}, // M 257 | ecbs{30, []ecb{ecb{4, 122}, ecb{18, 123}}}, // L 258 | ecbs{30, []ecb{ecb{42, 15}, ecb{32, 16}}}, // H 259 | ecbs{30, []ecb{ecb{48, 24}, ecb{14, 25}}}, // Q 260 | }, 261 | [4]ecbs{ // 39 262 | ecbs{28, []ecb{ecb{40, 47}, ecb{7, 48}}}, // M 263 | ecbs{30, []ecb{ecb{20, 117}, ecb{4, 118}}}, // L 264 | ecbs{30, []ecb{ecb{10, 15}, ecb{67, 16}}}, // H 265 | ecbs{30, []ecb{ecb{43, 24}, ecb{22, 25}}}, // Q 266 | }, 267 | [4]ecbs{ // 40 268 | ecbs{28, []ecb{ecb{18, 47}, ecb{31, 48}}}, // M 269 | ecbs{30, []ecb{ecb{19, 118}, ecb{6, 119}}}, // L 270 | ecbs{30, []ecb{ecb{20, 15}, ecb{61, 16}}}, // H 271 | ecbs{30, []ecb{ecb{34, 24}, ecb{34, 25}}}, // Q 272 | }, 273 | } 274 | ) 275 | 276 | func (v versionNumber) totalCodewords() int { 277 | total := 0 278 | ecCodewords := ecBlocks[v][1].codewordsPerBlock 279 | for _, block := range ecBlocks[v][1].blocks { 280 | total += block.count * (block.dataCodewords + ecCodewords) 281 | } 282 | return total 283 | } 284 | 285 | func (v versionNumber) dimension() int { 286 | return 17 + 4*int(v) 287 | } 288 | 289 | func chooseVersion(bitCount int, ecLevel ECLevel) (versionNumber, error) { 290 | for v := versionNumber(1); v <= 40; v++ { 291 | if (bitCount+7)/8 <= v.totalCodewords()-ecBlocks[v][ecLevel].totalECCodewords() { 292 | return v, nil 293 | } 294 | } 295 | return versionNumber(0), errors.New("Content too large") 296 | } 297 | --------------------------------------------------------------------------------